Merge branch 'master' into feature/golang

This commit is contained in:
Brandon Fish 2019-04-21 19:44:45 -05:00
commit f146cf1479
274 changed files with 24693 additions and 3453 deletions

View File

@ -2,8 +2,10 @@ version: "{build} ~ {branch}"
os: Visual Studio 2017 os: Visual Studio 2017
# Do not build feature branch with open Pull Requests branches:
skip_branch_with_pr: true only:
- staging
- trying
environment: environment:
matrix: matrix:
@ -14,30 +16,51 @@ environment:
cache: cache:
- 'C:\Users\appveyor\.cargo' - '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
# Install InnoSetup
- appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-08-22-is.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
- cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
before_deploy: before_deploy:
- cd ./src/installer - cd ./src/installer
- iscc wasmer.iss - iscc wasmer.iss
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe - copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe - appveyor PushArtifact ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- cd ..\..\
artifacts: matrix:
- path: WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe fast_finish: true
name: WasmerInstaller.exe
deploy: deploy:
description: 'WasmerInstaller' description: 'WasmerInstaller'

View File

@ -1,55 +1,85 @@
run_with_build_env_vars: &run_with_build_env_vars
environment:
LLVM_SYS_70_PREFIX: /home/circleci/project/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/
run_install_dependencies: &run_install_dependencies
run:
name: install dependencies
command: |
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
version: 2 version: 2
jobs: jobs:
changelog:
docker:
- image: docker:stable-git
steps:
- checkout
- run:
command: ! git diff --exit-code CHANGELOG.md
# Job used for testing # Job used for testing
lint: lint:
docker: docker:
- image: circleci/rust:latest - image: circleci/rust:latest
<<: *run_with_build_env_vars
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v6-lint-{{ arch }}-{{ checksum "Cargo.lock" }} - v8-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
- run: - v8-lint-{{ arch }}
name: Install dependencies - <<: *run_install_dependencies
command: |
sudo apt-get install -y cmake
- run: - run:
name: Install lint deps name: Install lint deps
command: | command: |
git config --global --unset url."ssh://git@github.com".insteadOf || true
rustup toolchain install nightly-2019-02-27
rustup component add rustfmt rustup component add rustfmt
rustup component add clippy rustup component add clippy --toolchain=nightly-2019-02-27 || cargo +nightly-2019-02-27 install --git https://github.com/rust-lang/rust-clippy/ --force clippy
- run: - run:
name: Execute lints name: Execute lints
command: make lint command: |
make lint
- save_cache: - save_cache:
paths: paths:
- /usr/local/cargo/registry - /usr/local/cargo/registry
- target/debug/.fingerprint - target/debug/.fingerprint
- target/debug/build - target/debug/build
- target/debug/deps - target/debug/deps
key: v6-lint-{{ arch }}-{{ checksum "Cargo.lock" }} key: v8-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
test: test:
docker: docker:
- image: circleci/rust:latest - image: circleci/rust:latest
<<: *run_with_build_env_vars
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v6-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }} - v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
- run: - v8-test-cargo-cache-linux-stable-{{ arch }}
name: Install dependencies - <<: *run_install_dependencies
- run:
name: Tests
command: make test
- run:
name: Emscripten Tests
command: | command: |
sudo apt-get install -y cmake make test-emscripten-clif
- run: make test make test-emscripten-llvm
- run: make integration-tests - run:
name: Integration Tests
command: make integration-tests
- save_cache: - save_cache:
paths: paths:
- /usr/local/cargo/registry - /usr/local/cargo/registry
- target/debug/.fingerprint - target/debug/.fingerprint
- target/debug/build - target/debug/build
- target/debug/deps - target/debug/deps
key: v6-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }} key: v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
test-macos: test-macos:
macos: macos:
@ -58,7 +88,8 @@ jobs:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v6-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }} - v8-cargo-cache-darwin-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
- v8-cargo-cache-darwin-stable-{{ arch }}
- run: - run:
name: Install crate dependencies name: Install crate dependencies
command: | command: |
@ -66,6 +97,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 +107,32 @@ 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-clif
make test-emscripten-llvm
- 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:
@ -96,7 +143,7 @@ jobs:
- target/release/.fingerprint - target/release/.fingerprint
- target/release/build - target/release/build
- target/release/deps - target/release/deps
key: v6-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }} key: v8-cargo-cache-darwin-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
test-and-build: test-and-build:
docker: docker:
@ -105,24 +152,43 @@ jobs:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v6-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }} - v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
- run: - v8-cargo-cache-linux-nightly-{{ arch }}
- run:
name: Install dependencies name: Install dependencies
command: | command: |
sudo apt-get install -y cmake sudo apt-get install -y cmake
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
# Use rust nightly (for singlepass, for now)
- run: rustup default nightly-2019-04-11
- run: - run:
name: Execute tests name: Tests
command: make test
- run:
name: Make release build
command: | command: |
make release 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-clif
make test-emscripten-llvm
- run:
name: Release Build
command: |
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
make production-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)
# GIT_VERSION=$(git describe --exact-match --tags) # GIT_VERSION=$(git describe --exact-match --tags)
echo "${VERSION}" >> artifacts/version echo "${VERSION}" >> artifacts/version
echo "${CIRCLE_TAG}" >> artifacts/git_version echo "${CIRCLE_TAG}" >> artifacts/git_version
cp ./target/release/wasmer ./artifacts/$(./binary-name.sh) make build-install
cp ./wasmer.tar.gz ./artifacts/$(./binary-name.sh)
- run:
name: Debug flag checked
command: |
cargo check --features "debug"
- persist_to_workspace: - persist_to_workspace:
root: . root: .
paths: paths:
@ -136,7 +202,7 @@ jobs:
- target/release/.fingerprint - target/release/.fingerprint
- target/release/build - target/release/build
- target/release/deps - target/release/deps
key: v6-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }} key: v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
test-and-build-macos: test-and-build-macos:
macos: macos:
@ -145,7 +211,8 @@ jobs:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v6-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }} - v8-cargo-cache-darwin-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
- v8-cargo-cache-darwin-nightly-{{ arch }}
- run: - run:
name: Install crate dependencies name: Install crate dependencies
command: | command: |
@ -153,31 +220,54 @@ 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: |
curl https://sh.rustup.rs -sSf | sh -s -- -y curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly-2019-04-11
export PATH="$HOME/.cargo/bin:$PATH" export PATH="$HOME/.cargo/bin:$PATH"
cargo --version cargo --version
# Use rust nightly (for singlepass, for now)
# - run:
# name: Install Rust nightly
# command: |
# export PATH="$HOME/.rustup/bin:$PATH"
# rustup default nightly-2019-04-11
- 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"
make release 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-clif
make test-emscripten-singlepass
- 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 production-release
mkdir -p artifacts mkdir -p artifacts
make build-install
cp ./wasmer.tar.gz ./artifacts/$(./binary-name.sh)
# VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2) # VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
# echo "${VERSION}" >> artifacts/version # echo "${VERSION}" >> artifacts/version
cp ./target/release/wasmer ./artifacts/$(./binary-name.sh)
- persist_to_workspace: - persist_to_workspace:
root: . root: .
paths: paths:
@ -191,7 +281,7 @@ jobs:
- target/release/.fingerprint - target/release/.fingerprint
- target/release/build - target/release/build
- target/release/deps - target/release/deps
key: v6-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }} key: v8-cargo-cache-darwin-nightly-{ arch }}-{{ checksum "Cargo.lock" }}
test-rust-nightly: test-rust-nightly:
docker: docker:
@ -200,20 +290,28 @@ jobs:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v6-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly - v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
- run: - v8-cargo-cache-linux-nightly-{{ arch }}
- run:
name: Install dependencies name: Install dependencies
command: | command: |
sudo apt-get install -y cmake sudo apt-get install -y cmake
- run: rustup default nightly 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 test tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
- run: rustup default nightly-2019-04-11
- run: |
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
make test
make test-singlepass
make test-emscripten-clif
make test-emscripten-singlepass
- save_cache: - save_cache:
paths: paths:
- /usr/local/cargo/registry - /usr/local/cargo/registry
- target/debug/.fingerprint - target/debug/.fingerprint
- target/debug/build - target/debug/build
- target/debug/deps - target/debug/deps
key: v6-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly key: v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly
publish-github-release: publish-github-release:
docker: docker:
@ -240,32 +338,57 @@ jobs:
# echo "Versions don't match. Wasmer output version (wasmer --version) is ${VERSION} while Git tag is ${VERSION_TAG}" # echo "Versions don't match. Wasmer output version (wasmer --version) is ${VERSION} while Git tag is ${VERSION_TAG}"
# exit 1 # exit 1
#fi #fi
trigger-benchmark-build:
docker:
- image: circleci/rust:latest
steps:
- run:
name: "Trigger Benchmark Build"
command: |
if [[ -z "${CIRCLE_API_USER_TOKEN}" ]]; then
echo "CIRCLE_API_USER_TOKEN environment variable not set"
exit 1
else
echo "Triggering benchmark build"
curl -u ${CIRCLE_API_USER_TOKEN} \
-d build_parameters[CIRCLE_JOB]=bench \
https://circleci.com/api/v1.1/project/github/wasmerio/wasmer-bench/tree/master
fi
workflows: workflows:
version: 2 version: 2
main: main:
jobs: jobs:
- changelog
- lint - lint
- 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
@ -274,3 +397,10 @@ workflows:
filters: filters:
branches: branches:
only: master only: master
- trigger-benchmark-build:
requires:
- test-and-build
- lint
filters:
branches:
only: master

6
.dockerignore Normal file
View File

@ -0,0 +1,6 @@
# Ignore everything
**
!lib/**
!src/**
!Cargo.toml
!Cargo.lock

43
.github/ISSUE_TEMPLATE/---bug-report.md vendored Normal file
View 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.

View 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
View 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.

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
/artifacts /artifacts
.DS_Store .DS_Store
.idea .idea
**/.vscode
install/

18
CHANGELOG.md Normal file
View File

@ -0,0 +1,18 @@
# Changelog
All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.
## **[Unreleased]**
- [#371](https://github.com/wasmerio/wasmer/pull/371) Add more Debug impl for WASI types
- [#368](https://github.com/wasmerio/wasmer/pull/368) Fix issue with write buffering
- [#343](https://github.com/wasmerio/wasmer/pull/343) Implement preopened files for WASI and fix aligment issue when accessing WASI memory
- [#367](https://github.com/wasmerio/wasmer/pull/367) Add caching support to the LLVM backend.
- [#366](https://github.com/wasmerio/wasmer/pull/366) Remove `UserTrapper` trait to fix [#365](https://github.com/wasmerio/wasmer/issues/365).
- [#348](https://github.com/wasmerio/wasmer/pull/348) Refactor internal runtime ↔️ backend abstraction.
- [#355](https://github.com/wasmerio/wasmer/pull/355) Misc changes to `Cargo.toml`s for publishing
- [#352](https://github.com/wasmerio/wasmer/pull/352) Bump version numbers to 0.3.0
- [#351](https://github.com/wasmerio/wasmer/pull/351) Add hidden option to specify wasm program name (can be used to improve error messages)
- [#350](https://github.com/wasmerio/wasmer/pull/350) Enforce that CHANGELOG.md is updated through CI.
- [#349](https://github.com/wasmerio/wasmer/pull/349) Add [CHANGELOG.md](https://github.com/wasmerio/wasmer/blob/master/CHANGELOG.md).

1892
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "wasmer" name = "wasmer"
version = "0.2.0" version = "0.3.0"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"] authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018" edition = "2018"
repository = "https://github.com/wasmerio/wasmer" repository = "https://github.com/wasmerio/wasmer"
@ -19,24 +19,33 @@ include = [
] ]
[dependencies] [dependencies]
errno = "0.2.4"
structopt = "0.2.11" structopt = "0.2.11"
wabt = "0.7.2" wabt = "0.7.2"
hashbrown = "0.1.8"
wasmer-clif-backend = { path = "lib/clif-backend" } wasmer-clif-backend = { path = "lib/clif-backend" }
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
wasmer-runtime = { path = "lib/runtime" } wasmer-runtime = { path = "lib/runtime" }
wasmer-runtime-abi = { path = "lib/runtime-abi", optional = true }
wasmer-runtime-core = { path = "lib/runtime-core" } wasmer-runtime-core = { path = "lib/runtime-core" }
wasmer-emscripten = { path = "lib/emscripten" } wasmer-emscripten = { path = "lib/emscripten" }
wasmer-golang = { path = "lib/golang" } wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
wasmer-wasi = { path = "lib/wasi", optional = true }
[workspace] [workspace]
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/golang"] members = ["lib/clif-backend", "lib/singlepass-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi"]
[build-dependencies] [build-dependencies]
wabt = "0.7.2" wabt = "0.7.2"
glob = "0.2.11" glob = "0.2.11"
rustc_version = "0.2.3"
[features] [features]
default = ["fast-tests"] default = ["fast-tests", "wasi"]
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
debug = []
# This feature will allow cargo test to run much faster # This feature will allow cargo test to run much faster
fast-tests = [] fast-tests = []
"backend:llvm" = ["wasmer-llvm-backend"]
"backend:singlepass" = ["wasmer-singlepass-backend"]
wasi = ["wasmer-wasi"]
vfs = ["wasmer-runtime-abi"]

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM circleci/rust:1.33.0-stretch as wasmer-build-env
RUN sudo apt-get update && \
sudo apt-get install -y --no-install-recommends \
cmake \
&& sudo rm -rf /var/lib/apt/lists/*
RUN curl -SL https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz \
| tar -xJC /home/circleci
ENV LLVM_SYS_70_PREFIX /home/circleci/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/
FROM wasmer-build-env AS wasmer-debug-env
RUN sudo apt-get update && \
sudo apt-get install -y --no-install-recommends \
valgrind \
&& sudo rm -rf /var/lib/apt/lists/*
FROM wasmer-build-env AS wasmer-build
WORKDIR /home/circleci/wasmer
COPY . /home/circleci/wasmer
RUN sudo chmod -R 777 .
RUN cargo build --release
FROM debian:stretch AS wasmer
WORKDIR /root/
COPY --from=wasmer-build /home/circleci/wasmer/target/release/wasmer .
ENTRYPOINT ["./wasmer"]

View File

@ -1,4 +1,6 @@
Copyright (c) 2019 Syrus Akbary MIT License
Copyright (c) 2019 Wasmer, Inc. and its affiliates.
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

View File

@ -12,14 +12,11 @@ spectests:
emtests: emtests:
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten
capi:
WASM_EMSCRIPTEN_GENERATE_C_API_HEADERS=1 cargo build --manifest-path lib/runtime-c-api/Cargo.toml --features generate-c-api-headers
# clean: # clean:
# rm -rf artifacts # rm -rf artifacts
build: build:
cargo build cargo build --features debug
install: install:
cargo install --path . cargo install --path .
@ -31,22 +28,57 @@ integration-tests: release
lint: lint:
cargo fmt --all -- --check cargo fmt --all -- --check
cargo clippy --all cargo +nightly-2019-02-27 clippy --all
precommit: lint test precommit: lint test
build-install:
mkdir -p ./install/bin
cp ./target/release/wasmer ./install/bin/
tar -C ./install -zcvf wasmer.tar.gz bin/wasmer
# For installing the contents locally
do-install:
tar -C ~/.wasmer -zxvf wasmer.tar.gz
test: test:
# We use one thread so the emscripten stdouts doesn't collide # We use one thread so the emscripten stdouts doesn't collide
cargo test --all --exclude wasmer-runtime-c-api -- --test-threads=1 $(runargs) cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-singlepass-backend -- $(runargs)
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) # cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
cargo build -p wasmer-runtime-c-api cargo build -p wasmer-runtime-c-api
cargo test -p wasmer-runtime-c-api -- --nocapture cargo test -p wasmer-runtime-c-api -- --nocapture
test-singlepass:
cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass
test-emscripten-llvm:
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
test-emscripten-clif:
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
test-emscripten-singlepass:
cargo test --manifest-path lib/emscripten/Cargo.toml --features singlepass -- --test-threads=1 $(runargs)
singlepass-debug-release:
cargo +nightly build --features "backend:singlepass debug" --release
singlepass-release:
cargo +nightly build --features "backend:singlepass" --release
singlepass-build:
cargo +nightly build --features "backend:singlepass debug"
release: release:
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows # If you are in OS-X, you will need mingw-w64 for cross compiling to windows
# brew install mingw-w64 # brew install mingw-w64
cargo build --release cargo build --release
production-release:
cargo build --release --features backend:singlepass,backend:llvm
debug-release: debug-release:
cargo build --release --features "debug" cargo build --release --features "debug"

View File

@ -18,7 +18,7 @@
## 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 [WASI](https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/) and [Emscripten](https://emscripten.org/).
Install Wasmer with: Install Wasmer with:
@ -26,19 +26,29 @@ Install Wasmer with:
curl https://get.wasmer.io -sSfL | sh curl https://get.wasmer.io -sSfL | sh
``` ```
_**NEW ✨**: You can now embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how!_ Wasmer runtime can also be embedded in different languages, so you can use WebAssembly anywhere ✨:
* [**Rust**](https://github.com/wasmerio/wasmer-rust-example)
* [**C/C++**](https://github.com/wasmerio/wasmer-c-api)
* [**PHP**](https://github.com/wasmerio/php-ext-wasm)
* [**Python**](https://github.com/wasmerio/python-ext-wasm)
### 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 Lua, PHP, SQLite and nginx!_):
```sh ```sh
# Run Lua # Run Lua
wasmer run examples/lua.wasm wasmer run examples/lua.wasm
# Run PHP
wasmer run examples/php.wasm
# Run SQLite
wasmer run examples/sqlite.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
``` ```
@ -70,6 +80,7 @@ Please select your operating system:
- [macOS](#macos) - [macOS](#macos)
- [Debian-based Linuxes](#debian-based-linuxes) - [Debian-based Linuxes](#debian-based-linuxes)
- [FreeBSD](#freebsd)
- [Microsoft Windows](#windows-msvc) - [Microsoft Windows](#windows-msvc)
#### macOS #### macOS
@ -92,18 +103,30 @@ sudo port install cmake
sudo apt install cmake sudo apt install cmake
``` ```
#### FreeBSD
```sh
pkg install cmake
```
#### Windows (MSVC) #### Windows (MSVC)
Windows support is _highly experimental_. Only simple Wasm programs may be run, and no syscalls are allowed. This means Windows support is _highly experimental_. Only simple Wasm programs may be run, and no syscalls are allowed. This means
nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmerio/wasmer/issues/176) regarding Emscripten syscall polyfills 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)
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. Make sure to enable "Add python.exe to Path" during installation.
2. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default 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).
3. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH. 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
@ -158,6 +181,7 @@ Below are some of the goals of this project (in order of priority):
- [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 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 WASI _(in the works)_
- [ ] 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

View File

@ -23,8 +23,8 @@ initOS() {
darwin) OS='darwin';; darwin) OS='darwin';;
linux) OS='linux';; linux) OS='linux';;
freebsd) OS='freebsd';; freebsd) OS='freebsd';;
mingw*) OS='windows';; # mingw*) OS='windows';;
msys*) OS='windows';; # msys*) OS='windows';;
*) echo "OS ${OS} is not supported by this installation script"; exit 1;; *) echo "OS ${OS} is not supported by this installation script"; exit 1;;
esac esac
} }
@ -34,11 +34,11 @@ initArch
initOS initOS
# determine install directory if required # determine install directory if required
BINARY="wasmer-${OS}-${ARCH}" BINARY="wasmer-${OS}-${ARCH}.tar.gz"
# add .exe if on windows # add .exe if on windows
if [ "$OS" = "windows" ]; then # if [ "$OS" = "windows" ]; then
BINARY="$BINARY.exe" # BINARY="$BINARY.exe"
fi # fi
echo "${BINARY}" echo "${BINARY}"

10
bors.toml Normal file
View File

@ -0,0 +1,10 @@
status = [
"ci/circleci: lint",
"ci/circleci: test",
"ci/circleci: test-macos",
"ci/circleci: test-rust-nightly",
"continuous-integration/appveyor/branch"
]
required_approvals = 1
timeout_sec = 900
delete_merged_branches = true

39
docs/docker.md Normal file
View File

@ -0,0 +1,39 @@
# Dockerfile Documentation
The `Dockerfile` included in the project root directory could be used for development purposes or to build a small image containing the `wasmer` executable.
The `wasmer-build-env` stage in the Dockerfile contains the dependencies needed to compile Wasmer including LLVM.
The `wasmer-debug-env` stage adds the `valgrind` profiling tool to the `wasmer-build-env` stage.
The `wasmer-build` stage in the Dockerfile will copy the current directory, assuming the build context is the `wasmer` project, and build the project using `cargo build --release`.
The `wasmer` stage will copy the resulting `wasmer` executable from the `wasmer-build` stage into a new base image to create a smaller image containing `wasmer`.
## Example Usages
### Wasmer image
1. From the `wasmer` project directory, build the image:
`docker build -t wasmer --target=wasmer .`
2. List options:
`docker run wasmer --help`
3. Mount a directory, and run an example wasm file:
`docker run -v /Users/admin/Documents/wasmer-workspace:/root/wasmer-workspace wasmer run /root/wasmer-workspace/examples/hello.wasm`
### Profiling
1. Build `wasmer-debug-env`:
`docker build --tag=wasmer-debug-env --target wasmer-debug-env .`
2. Mount a directory from the host and run interactively:
`docker run -it -v /Users/admin/Documents/wasmer-workspace:/home/circleci/wasmer-workspace wasmer-debug-env /bin/bash`
3. Inside the container, build `wasmer` and run profiling tool:
```
cd /home/circleci/wasmer-workspace/wasmer`
cargo build
valgrind --tool=callgrind --dump-instr=yes --collect-jumps=yes --simulate-cache=yes target/debug/wasmer run test.wasm
```
The `callgrind.out` can be viewed with the `qcachegrind` tool on Mac OS (`brew install qcachegrind`).

Binary file not shown.

26
examples/nginx/LICENSE Normal file
View 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.
*/

BIN
examples/php.wasm Normal file

Binary file not shown.

View File

@ -0,0 +1,37 @@
(module
(func $main (export "main")
(i32.eq (call $test (i32.const 0)) (i32.const 2))
(i32.eq (call $test (i32.const 1)) (i32.const 0))
(i32.eq (call $test (i32.const 2)) (i32.const 1))
(i32.eq (call $test (i32.const 3)) (i32.const 3))
(i32.eq (call $test (i32.const 4)) (i32.const 3))
(i32.and)
(i32.and)
(i32.and)
(i32.and)
(i32.const 1)
(i32.eq)
(br_if 0)
(unreachable)
)
(func $test (param $p i32) (result i32)
(block
(block
(block
(block
(block
(get_local $p)
(br_table 2 0 1 3)
)
(return (i32.const 0))
)
(return (i32.const 1))
)
(return (i32.const 2))
)
(return (i32.const 3))
)
(unreachable)
)
)

View File

@ -0,0 +1,23 @@
(module
(func $main (export "main")
(local $a i32)
(block
(set_local $a (i32.const 33))
(i32.const 11)
(call $foo (get_local $a))
(i32.add)
(i32.const 86)
(i32.eq)
(br_if 0)
(unreachable)
)
)
(func $foo (param $input i32) (result i32)
(local $a i32)
(set_local $a (i32.const 42))
(get_local $a)
(get_local $input)
(i32.add)
)
)

View File

@ -0,0 +1,25 @@
(module
(type $binop (func (param i32 i32) (result i32)))
(table 1 100 anyfunc)
(elem (i32.const 5) $sub)
(elem (i32.const 10) $add)
(func $main (export "main")
(if (i32.eq (call_indirect (type $binop) (i32.const 42) (i32.const 1) (i32.const 10)) (i32.const 43))
(then)
(else unreachable)
)
(if (i32.eq (call_indirect (type $binop) (i32.const 42) (i32.const 1) (i32.const 5)) (i32.const 41))
(then)
(else unreachable)
)
)
(func $add (param i32) (param i32) (result i32)
(i32.add (get_local 0) (get_local 1))
)
(func $sub (param i32) (param i32) (result i32)
(i32.sub (get_local 0) (get_local 1))
)
)

View File

@ -0,0 +1,36 @@
(module
(func $main (export "main")
(i32.const 1)
(if (i32.ne (i32.div_s (i32.const 2) (i32.const -1)) (i32.const -2))
(then unreachable)
)
(i32.const 2)
(if (i32.ne (i32.div_u (i32.const 2) (i32.const -1)) (i32.const 0))
(then unreachable)
)
(i32.const 3)
(if (i32.ne (i32.div_u (i32.const 10) (i32.const 5)) (i32.const 2))
(then unreachable)
)
(i32.const 4)
(if (i64.ne (i64.div_s (i64.const 300000000000) (i64.const -1)) (i64.const -300000000000))
(then unreachable)
)
(i32.const 5)
(if (i64.ne (i64.div_u (i64.const 300000000000) (i64.const -1)) (i64.const 0))
(then unreachable)
)
(i32.const 6)
(if (i64.ne (i64.div_u (i64.const 300000000000) (i64.const 2)) (i64.const 150000000000))
(then unreachable)
)
(i32.add)
(i32.add)
(i32.add)
(i32.add)
(i32.add)
(if (i32.ne (i32.const 21))
(then unreachable)
)
)
)

View File

@ -0,0 +1,26 @@
(module
(global $g1 (mut i32) (i32.const 0))
(global $g2 (mut i32) (i32.const 99))
(func $main (export "main")
(if (i32.eq (get_global $g1) (i32.const 0))
(then)
(else unreachable)
)
(if (i32.eq (get_global $g2) (i32.const 99))
(then)
(else unreachable)
)
(set_global $g1 (i32.add (get_global $g1) (i32.const 1)))
(set_global $g2 (i32.sub (get_global $g2) (i32.const 1)))
(if (i32.eq (get_global $g1) (i32.const 1))
(then)
(else unreachable)
)
(if (i32.eq (get_global $g2) (i32.const 98))
(then)
(else unreachable)
)
)
)

View File

@ -0,0 +1,44 @@
(module
(func $main (export "main") (result i32)
(local $v1 i32)
(block
(i32.const 10)
(set_local $v1)
(i32.const 42)
(get_local $v1)
(i32.add)
(i32.const 53)
(i32.eq)
(br_if 0)
(i32.const 1)
(i32.const -100)
(i32.const 41)
(i32.lt_s)
(i32.sub)
(br_if 0)
(i32.const -100)
(i32.const 41)
(i32.lt_u)
(br_if 0)
(i32.const 1)
(i32.const 100)
(i32.const -41)
(i32.gt_s)
(i32.sub)
(br_if 0)
(i32.const 100)
(i32.const -41)
(i32.gt_u)
(br_if 0)
(i32.const 0)
(return)
)
(unreachable)
)
)

View File

@ -0,0 +1,48 @@
(module
(func $main (export "main") (result i64)
(local $v1 i64)
(block
(i64.const 10)
(set_local $v1)
(i64.const 42)
(get_local $v1)
(i64.add)
(i64.const 53)
(i64.eq)
(br_if 0)
(i64.const 1)
(i64.const -100)
(i64.const 41)
(i64.lt_s)
(i64.extend_u/i32)
(i64.sub)
(i32.wrap/i64)
(br_if 0)
(i64.const -100)
(i64.const 41)
(i64.lt_u)
(br_if 0)
(i64.const 1)
(i64.const 100)
(i64.const -41)
(i64.gt_s)
(i64.extend_u/i32)
(i64.sub)
(i32.wrap/i64)
(br_if 0)
(i64.const 100)
(i64.const -41)
(i64.gt_u)
(br_if 0)
(i64.const 0)
(return)
)
(unreachable)
)
)

View File

@ -0,0 +1,33 @@
(module
(func $main (export "main")
(local $a i32)
(set_local $a (i32.const 33))
(block
(call $foo (if (result i32) (i32.eq (get_local $a) (i32.const 33))
(then (i32.const 1))
(else (i32.const 2))
))
(i32.eq (i32.const 43))
(br_if 0)
(unreachable)
)
(block
(call $foo (if (result i32) (i32.eq (get_local $a) (i32.const 30))
(then (i32.const 1))
(else (i32.const 2))
))
(i32.eq (i32.const 44))
(br_if 0)
(unreachable)
)
)
(func $foo (param $input i32) (result i32)
(local $a i32)
(set_local $a (i32.const 42))
(get_local $a)
(get_local $input)
(i32.add)
)
)

View File

@ -0,0 +1,17 @@
(module
(func $main (export "main")
(local $count i32)
(local $sum i32)
(loop (result i32)
(set_local $count (i32.add (get_local $count) (i32.const 1)))
(set_local $sum (i32.add (get_local $sum) (get_local $count)))
(i32.sub (i32.const 1) (i32.eq
(get_local $count)
(i32.const 50000)
))
(br_if 0)
(get_local $sum)
)
(if (i32.ne (i32.const 1250025000)) (unreachable))
)
)

View File

@ -0,0 +1,90 @@
(module
(memory 1)
(func $main (export "main")
(call $test_stack_layout)
)
(func $test_stack_layout
(local $addr i32)
(set_local $addr (i32.const 16))
(i32.store (get_local $addr) (i32.const 10))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 655360))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 11))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 720896))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 12))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 786432))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 13))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 851968))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 14))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 917504))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 15))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 983040))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 16))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1048576))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 17))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1114112))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 18))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1179648))
(then)
(else (unreachable))
)
(i32.const 1)
(i32.store (get_local $addr) (i32.const 19))
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1245184))
(then)
(else (unreachable))
)
(drop)
(drop)
(drop)
(drop)
(drop)
(drop)
(drop)
(drop)
(drop)
)
)

View File

@ -0,0 +1,20 @@
(module
(func $main (export "main")
(if (i32.eq (select
(i32.const 10)
(i32.const 20)
(i32.const 1)
) (i32.const 10))
(then)
(else (unreachable))
)
(if (i32.eq (select
(i32.const 10)
(i32.const 20)
(i32.const 0)
) (i32.const 20))
(then)
(else (unreachable))
)
)
)

View File

@ -0,0 +1,11 @@
(module
(func $main (export "main")
(local $x i32)
(tee_local $x (i32.const 3))
(i32.add (i32.const 4))
(if (i32.eq (i32.const 7))
(then)
(else unreachable)
)
)
)

View File

@ -0,0 +1,38 @@
(module
(func $main (export "main")
(i32.const 5)
(block (result i32)
(i32.const 10)
(block
(i32.const 20)
(block
(i32.const 50)
(br 1)
)
(unreachable)
)
)
(i32.add)
(if (i32.eq (i32.const 15))
(then)
(else unreachable)
)
(block (result i32)
(i32.const 10)
(block (result i32)
(i32.const 20)
(block
(i32.const 50)
(br 1)
)
(unreachable)
)
(i32.add)
)
(if (i32.eq (i32.const 60))
(then)
(else unreachable)
)
)
)

BIN
examples/sqlite.wasm Normal file

Binary file not shown.

View File

@ -32,6 +32,7 @@ white="\033[37m"
bold="\e[1m" bold="\e[1m"
dim="\e[2m" dim="\e[2m"
# Warning: Remove this on the public repo
RELEASES_URL="https://github.com/wasmerio/wasmer/releases" RELEASES_URL="https://github.com/wasmerio/wasmer/releases"
wasmer_download_json() { wasmer_download_json() {
@ -133,7 +134,7 @@ wasmer_link() {
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"\$HOME/.wasmer\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\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"
@ -369,12 +370,12 @@ wasmer_download() {
WASMER=INSTALL_DIRECTORY WASMER=INSTALL_DIRECTORY
# assemble expected release artifact name # assemble expected release artifact name
BINARY="wasmer-${OS}-${ARCH}" BINARY="wasmer-${OS}-${ARCH}.tar.gz"
# add .exe if on windows # add .exe if on windows
if [ "$OS" = "windows" ]; then # if [ "$OS" = "windows" ]; then
BINARY="$BINARY.exe" # BINARY="$BINARY.exe"
fi # fi
# if WASMER_RELEASE_TAG was not provided, assume latest # if WASMER_RELEASE_TAG was not provided, assume latest
if [ -z "$WASMER_RELEASE_TAG" ]; then if [ -z "$WASMER_RELEASE_TAG" ]; then
@ -417,9 +418,6 @@ wasmer_download() {
printf "\033[K\n\033[1A" printf "\033[K\n\033[1A"
# printf "\033[1A$cyan> Downloaded$reset\033[K\n" # printf "\033[1A$cyan> Downloaded$reset\033[K\n"
# echo "Setting executable permissions." # echo "Setting executable permissions."
chmod +x "$DOWNLOAD_FILE"
INSTALL_NAME="wasmer"
# windows not supported yet # windows not supported yet
# if [ "$OS" = "windows" ]; then # if [ "$OS" = "windows" ]; then
@ -428,8 +426,9 @@ wasmer_download() {
# echo "Moving executable to $INSTALL_DIRECTORY/$INSTALL_NAME" # echo "Moving executable to $INSTALL_DIRECTORY/$INSTALL_NAME"
mkdir -p $INSTALL_DIRECTORY/bin mkdir -p $INSTALL_DIRECTORY
mv "$DOWNLOAD_FILE" "$INSTALL_DIRECTORY/bin/$INSTALL_NAME" # Untar the wasmer contents in the install directory
tar -C $INSTALL_DIRECTORY -zxvf $DOWNLOAD_FILE
} }
wasmer_verify_or_quit() { wasmer_verify_or_quit() {

View File

@ -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

View File

@ -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

View File

@ -22,7 +22,8 @@ The integration builds on the Wasmer runtime and allow us to run WebAssembly fil
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). - [WASI](./wasi): run WebAssembly files with the [WASI ABI](https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/).
- [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: _research period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_ - Blazor: _research period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_
@ -31,6 +32,8 @@ Wasmer intends to support different integrations:
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 best fit their use case. 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 - [singlepass-backend](./singlepass-backend/): Single pass backend - super fast compilation, slower runtime speed
- [clif-backend](./clif-backend/): Cranelift backend - slower compilation, normal runtime speed
- [llvm-backend](./llvm-backend/): LLVM backend - slow compilation, native runtime speed

View File

@ -1,6 +1,6 @@
[package] [package]
name = "wasmer-clif-backend" name = "wasmer-clif-backend"
version = "0.1.2" version = "0.3.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,17 +8,18 @@ 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.3.0" }
cranelift-native = "0.26.0" cranelift-native = "0.30.0"
cranelift-codegen = "0.26.0" cranelift-codegen = "0.30.0"
cranelift-entity = "0.26.0" cranelift-entity = "0.30.0"
cranelift-wasm = "0.26.0" cranelift-wasm = "0.30.0"
hashbrown = "0.1" hashbrown = "0.1"
target-lexicon = "0.2.0" target-lexicon = "0.3.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]
@ -32,7 +33,7 @@ version = "0.0.7"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" } wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.3.0" }
[features] [features]
debug = ["wasmer-runtime-core/debug"] debug = ["wasmer-runtime-core/debug"]

View File

@ -0,0 +1,31 @@
<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://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://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">
<img src="https://withspectrum.github.io/badge/badge.svg" alt="Join the Wasmer Community">
</a>
<a href="https://crates.io/crates/wasmer-clif-backend">
<img src="https://img.shields.io/crates/d/wasmer-clif-backend.svg" alt="Number of downloads from crates.io">
</a>
<a href="https://docs.rs/wasmer-clif-backend">
<img src="https://docs.rs/wasmer-clif-backend/badge.svg" alt="Read our API documentation">
</a>
</p>
# Wasmer Cranelift backend
Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
compatible with Emscripten, Rust and Go. [Learn
more](https://github.com/wasmerio/wasmer).
This crate represents the Cranelift backend.

View File

@ -27,18 +27,12 @@ impl CacheGenerator {
} }
impl CacheGen for CacheGenerator { impl CacheGen for CacheGenerator {
fn generate_cache( fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), Error> {
&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, // Clone the memory to a new location. This could take a long time,
// depending on the throughput of your memcpy implementation. // depending on the throughput of your memcpy implementation.
let compiled_code = (*self.memory).clone(); let compiled_code = (*self.memory).clone();
Ok(( Ok((
info,
self.backend_cache.into_backend_data()?.into_boxed_slice(), self.backend_cache.into_backend_data()?.into_boxed_slice(),
compiled_code, compiled_code,
)) ))

View File

@ -445,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]
@ -477,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.info) { 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
@ -490,10 +497,28 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
args.push(vmctx); args.push(vmctx);
args.extend(call_args.iter().cloned()); 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);

View File

@ -16,7 +16,7 @@ use target_lexicon::Triple;
use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{Compiler, Token}, backend::{Compiler, CompilerConfig, Token},
error::{CompileError, CompileResult}, error::{CompileError, CompileResult},
module::ModuleInner, module::ModuleInner,
}; };
@ -24,6 +24,7 @@ use wasmer_runtime_core::{
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate rayon;
extern crate serde; extern crate serde;
use wasmparser::{self, WasmDecoder}; use wasmparser::{self, WasmDecoder};
@ -38,12 +39,17 @@ impl CraneliftCompiler {
impl Compiler for CraneliftCompiler { impl Compiler for CraneliftCompiler {
/// Compiles wasm binary to a wasmer module. /// Compiles wasm binary to a wasmer module.
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner> { fn compile(
&self,
wasm: &[u8],
compiler_config: CompilerConfig,
_: Token,
) -> CompileResult<ModuleInner> {
validate(wasm)?; validate(wasm)?;
let isa = get_isa(); let isa = get_isa();
let mut module = module::Module::new(wasm); let mut module = module::Module::new(&compiler_config);
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)?;

View File

@ -10,7 +10,7 @@ use std::sync::Arc;
use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::Backend, backend::{Backend, CompilerConfig},
error::CompileResult, error::CompileResult,
module::{ModuleInfo, ModuleInner, StringTable}, module::{ModuleInfo, ModuleInner, StringTable},
structures::{Map, TypedIndex}, structures::{Map, TypedIndex},
@ -25,7 +25,7 @@ pub struct Module {
} }
impl Module { impl Module {
pub fn new(wasm: &[u8]) -> Self { pub fn new(compiler_config: &CompilerConfig) -> Self {
Self { Self {
info: ModuleInfo { info: ModuleInfo {
memories: Map::new(), memories: Map::new(),
@ -50,6 +50,9 @@ impl Module {
namespace_table: StringTable::new(), namespace_table: StringTable::new(),
name_table: StringTable::new(), name_table: StringTable::new(),
em_symbol_map: compiler_config.symbol_map.clone(),
custom_sections: HashMap::new(),
}, },
} }
} }
@ -70,16 +73,15 @@ impl Module {
handler_data.clone(), handler_data.clone(),
)?; )?;
let protected_caller = Caller::new(&self.info, handler_data, trampolines);
let cache_gen = Box::new(CacheGenerator::new( let cache_gen = Box::new(CacheGenerator::new(
backend_cache, backend_cache,
Arc::clone(&func_resolver.memory), Arc::clone(&func_resolver.memory),
)); ));
let runnable_module = Caller::new(handler_data, trampolines, func_resolver);
Ok(ModuleInner { Ok(ModuleInner {
func_resolver: Box::new(func_resolver), runnable_module: Box::new(runnable_module),
protected_caller: Box::new(protected_caller),
cache_gen, cache_gen,
info: self.info, info: self.info,
@ -100,16 +102,15 @@ impl Module {
) )
.map_err(|e| CacheError::Unknown(format!("{:?}", e)))?; .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?;
let protected_caller = Caller::new(&info, handler_data, trampolines);
let cache_gen = Box::new(CacheGenerator::new( let cache_gen = Box::new(CacheGenerator::new(
backend_cache, backend_cache,
Arc::clone(&func_resolver.memory), Arc::clone(&func_resolver.memory),
)); ));
let runnable_module = Caller::new(handler_data, trampolines, func_resolver);
Ok(ModuleInner { Ok(ModuleInner {
func_resolver: Box::new(func_resolver), runnable_module: Box::new(runnable_module),
protected_caller: Box::new(protected_caller),
cache_gen, cache_gen,
info, info,
@ -148,8 +149,8 @@ convert_clif_to_runtime_index![
(SignatureIndex: SigIndex), (SignatureIndex: SigIndex),
]; ];
impl<'a> From<Converter<&'a ir::Signature>> for FuncSig { impl From<Converter<ir::Signature>> for FuncSig {
fn from(signature: Converter<&'a ir::Signature>) -> Self { fn from(signature: Converter<ir::Signature>) -> Self {
FuncSig::new( FuncSig::new(
signature signature
.0 .0

View File

@ -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::{
@ -51,6 +50,20 @@ impl<'module, 'isa> ModuleEnv<'module, 'isa> {
Ok(self.func_bodies) Ok(self.func_bodies)
} }
/// Return the global for the given global index.
pub fn get_global(&self, global_index: cranelift_wasm::GlobalIndex) -> &cranelift_wasm::Global {
&self.globals[Converter(global_index).into()]
}
/// Return the signature index for the given function index.
pub fn get_func_type(
&self,
func_index: cranelift_wasm::FuncIndex,
) -> cranelift_wasm::SignatureIndex {
let sig_index: SigIndex = self.module.info.func_assoc[Converter(func_index).into()];
Converter(sig_index).into()
}
} }
impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> { impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> {
@ -60,17 +73,9 @@ 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.
fn get_signature(&self, clif_sig_index: cranelift_wasm::SignatureIndex) -> &ir::Signature {
&self.signatures[Converter(clif_sig_index).into()]
} }
/// Declares a function import to the environment. /// Declares a function import to the environment.
@ -96,11 +101,6 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
}); });
} }
/// Return the number of imported funcs.
fn get_num_func_imports(&self) -> usize {
self.module.info.imported_functions.len()
}
/// Declares the type (signature) of a local function in the module. /// Declares the type (signature) of a local function in the module.
fn declare_func_type(&mut self, clif_sig_index: cranelift_wasm::SignatureIndex) { fn declare_func_type(&mut self, clif_sig_index: cranelift_wasm::SignatureIndex) {
// We convert the cranelift signature index to // We convert the cranelift signature index to
@ -110,15 +110,6 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
self.module.info.func_assoc.push(sig_index); self.module.info.func_assoc.push(sig_index);
} }
/// Return the signature index for the given function index.
fn get_func_type(
&self,
func_index: cranelift_wasm::FuncIndex,
) -> cranelift_wasm::SignatureIndex {
let sig_index: SigIndex = self.module.info.func_assoc[Converter(func_index).into()];
Converter(sig_index).into()
}
/// Declares a global to the environment. /// Declares a global to the environment.
fn declare_global(&mut self, global: cranelift_wasm::Global) { fn declare_global(&mut self, global: cranelift_wasm::Global) {
let desc = GlobalDescriptor { let desc = GlobalDescriptor {
@ -184,11 +175,6 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
self.globals.push(global); self.globals.push(global);
} }
/// Return the global for the given global index.
fn get_global(&self, global_index: cranelift_wasm::GlobalIndex) -> &cranelift_wasm::Global {
&self.globals[Converter(global_index).into()]
}
/// Declares a table to the environment. /// Declares a table to the environment.
fn declare_table(&mut self, table: cranelift_wasm::Table) { fn declare_table(&mut self, table: cranelift_wasm::Table) {
use cranelift_wasm::TableElementType; use cranelift_wasm::TableElementType;
@ -242,7 +228,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
table_index: cranelift_wasm::TableIndex, table_index: cranelift_wasm::TableIndex,
base: Option<cranelift_wasm::GlobalIndex>, base: Option<cranelift_wasm::GlobalIndex>,
offset: usize, offset: usize,
elements: Vec<cranelift_wasm::FuncIndex>, elements: Box<[cranelift_wasm::FuncIndex]>,
) { ) {
// Convert Cranelift GlobalIndex to wamser GlobalIndex // Convert Cranelift GlobalIndex to wamser GlobalIndex
// let base = base.map(|index| WasmerGlobalIndex::new(index.index())); // let base = base.map(|index| WasmerGlobalIndex::new(index.index()));
@ -380,7 +366,11 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
} }
/// Provides the contents of a function body. /// Provides the contents of a function body.
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> cranelift_wasm::WasmResult<()> { fn define_function_body(
&mut self,
body_bytes: &'data [u8],
body_offset: usize,
) -> cranelift_wasm::WasmResult<()> {
let mut func_translator = FuncTranslator::new(); let mut func_translator = FuncTranslator::new();
let func_body = { let func_body = {
@ -394,7 +384,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
let mut func = ir::Function::with_name_signature(name, sig); let mut func = ir::Function::with_name_signature(name, sig);
func_translator.translate(body_bytes, &mut func, &mut func_env)?; func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?;
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
{ {
@ -534,7 +524,10 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
.special_param(ir::ArgumentPurpose::VMContext) .special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter"); .expect("missing vmctx parameter");
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 + self.module.info.imported_functions.len() as i64,
);
pos.ins().call(start_debug, &[vmctx, func_index]); pos.ins().call(start_debug, &[vmctx, func_index]);

View File

@ -224,6 +224,7 @@ pub enum TrapCode {
IntegerDivisionByZero, IntegerDivisionByZero,
BadConversionToInteger, BadConversionToInteger,
Interrupt, Interrupt,
UnreachableCodeReached,
User(u16), User(u16),
} }
@ -297,6 +298,7 @@ impl binemit::TrapSink for LocalTrapSink {
ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero, ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero,
ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger, ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger,
ir::TrapCode::Interrupt => TrapCode::Interrupt, ir::TrapCode::Interrupt => TrapCode::Interrupt,
ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached,
ir::TrapCode::User(x) => TrapCode::User(x), ir::TrapCode::User(x) => TrapCode::User(x),
}; };

View File

@ -7,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};
@ -20,7 +21,6 @@ use wasmer_runtime_core::cache::Error as CacheError;
use wasmer_runtime_core::{ use wasmer_runtime_core::{
self, self,
backend::{ backend::{
self,
sys::{Memory, Protect}, sys::{Memory, Protect},
SigRegistry, SigRegistry,
}, },
@ -92,25 +92,44 @@ impl FuncResolverBuilder {
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 mut local_trap_sink = LocalTrapSink::new();
let mut ctx = Context::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();
ctx.compile_and_emit(
isa,
&mut code_buf,
&mut reloc_sink,
&mut local_trap_sink,
)
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
ctx.clear();
Ok((code_buf, (reloc_sink, local_trap_sink)))
},
)
.collect();
let compiled_functions = compiled_functions?;
let mut total_size = 0; let mut total_size = 0;
// We separate into two iterators, one iterable and one into iterable
for (_, func) in function_bodies { let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
ctx.func = func; compiled_functions.into_iter().unzip();
let mut code_buf = Vec::new(); for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
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() })?;
ctx.clear();
// 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);
@ -118,7 +137,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());
} }
@ -145,10 +163,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()]
@ -202,7 +220,7 @@ impl FuncResolverBuilder {
pub fn finalize( pub fn finalize(
mut self, mut self,
signatures: &SliceMap<SigIndex, Arc<FuncSig>>, signatures: &SliceMap<SigIndex, FuncSig>,
trampolines: Arc<Trampolines>, trampolines: Arc<Trampolines>,
handler_data: HandlerData, handler_data: HandlerData,
) -> CompileResult<(FuncResolver, BackendCache)> { ) -> CompileResult<(FuncResolver, BackendCache)> {
@ -269,8 +287,8 @@ 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 _
} }
}; };
@ -338,13 +356,8 @@ pub struct FuncResolver {
pub(crate) memory: Arc<Memory>, pub(crate) memory: Arc<Memory>,
} }
// Implements FuncResolver trait. impl FuncResolver {
impl backend::FuncResolver for FuncResolver { pub fn lookup(&self, index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
fn get(
&self,
_module: &wasmer_runtime_core::module::ModuleInner,
index: LocalFuncIndex,
) -> Option<NonNull<vm::Func>> {
lookup_func(&self.map, &self.memory, index) lookup_func(&self.map, &self.memory, index)
} }
} }
@ -355,20 +368,26 @@ fn round_up(n: usize, multiple: usize) -> usize {
} }
extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) { extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) {
print!(" i32: {},", n); eprint!(" i32: {},", n);
} }
extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) { extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) {
print!(" i64: {},", n); eprint!(" i64: {},", n);
} }
extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) { extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) {
print!(" f32: {},", n); eprint!(" f32: {},", n);
} }
extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) { extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) {
print!(" f64: {},", n); eprint!(" f64: {},", n);
} }
extern "C" fn start_debug(_ctx: &mut vm::Ctx, func_index: u32) { extern "C" fn start_debug(ctx: &mut vm::Ctx, func_index: u32) {
print!("func ({}), args: [", func_index); if let Some(symbol_map) = unsafe { ctx.borrow_symbol_map() } {
if let Some(fn_name) = symbol_map.get(&func_index) {
eprint!("func ({} ({})), args: [", fn_name, func_index);
return;
}
}
eprint!("func ({}), args: [", func_index);
} }
extern "C" fn end_debug(_ctx: &mut vm::Ctx) { extern "C" fn end_debug(_ctx: &mut vm::Ctx) {
println!(" ]"); eprintln!(" ]");
} }

View File

@ -1,15 +1,14 @@
use crate::relocation::{TrapData, TrapSink}; use crate::relocation::{TrapData, TrapSink};
use crate::resolver::FuncResolver;
use crate::trampoline::Trampolines; use crate::trampoline::Trampolines;
use hashbrown::HashSet;
use libc::c_void; use libc::c_void;
use std::{cell::Cell, sync::Arc}; use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{ProtectedCaller, Token, UserTrapper}, backend::RunnableModule,
error::RuntimeResult, module::ModuleInfo,
export::Context, typed_func::{Wasm, WasmTrapInfo},
module::{ExportIndex, ModuleInfo, ModuleInner}, types::{LocalFuncIndex, SigIndex},
types::{FuncIndex, FuncSig, LocalOrImport, SigIndex, Type, Value}, vm,
vm::{self, ImportBacking},
}; };
#[cfg(unix)] #[cfg(unix)]
@ -25,167 +24,78 @@ 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;
impl UserTrapper for Trapper {
unsafe fn do_early_trap(&self, msg: String) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
trigger_trap()
}
} }
pub struct Caller { pub struct Caller {
func_export_set: HashSet<FuncIndex>,
handler_data: HandlerData, handler_data: HandlerData,
trampolines: Arc<Trampolines>, trampolines: Arc<Trampolines>,
resolver: FuncResolver,
} }
impl Caller { impl Caller {
pub fn new( pub fn new(
module: &ModuleInfo,
handler_data: HandlerData, handler_data: HandlerData,
trampolines: Arc<Trampolines>, trampolines: Arc<Trampolines>,
resolver: FuncResolver,
) -> Self { ) -> Self {
let mut func_export_set = HashSet::new();
for export_index in module.exports.values() {
if let ExportIndex::Func(func_index) = export_index {
func_export_set.insert(*func_index);
}
}
if let Some(start_func_index) = module.start_func {
func_export_set.insert(start_func_index);
}
Self { Self {
func_export_set,
handler_data, handler_data,
trampolines, trampolines,
resolver,
} }
} }
} }
impl ProtectedCaller for Caller { impl RunnableModule for Caller {
fn call( fn get_func(&self, _: &ModuleInfo, func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
&self, self.resolver.lookup(func_index)
module: &ModuleInner, }
func_index: FuncIndex,
params: &[Value],
import_backing: &ImportBacking,
vmctx: *mut vm::Ctx,
_: Token,
) -> RuntimeResult<Vec<Value>> {
let (func_ptr, ctx, signature, sig_index) =
get_func_from_index(&module, import_backing, func_index);
let vmctx_ptr = match ctx { fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm> {
Context::External(external_vmctx) => external_vmctx, unsafe extern "C" fn invoke(
Context::Internal => vmctx, trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull<vm::Func>, *const u64, *mut u64),
}; ctx: *mut vm::Ctx,
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
_trap_info: *mut WasmTrapInfo,
invoke_env: Option<NonNull<c_void>>,
) -> bool {
let handler_data = &*invoke_env.unwrap().cast().as_ptr();
assert!(self.func_export_set.contains(&func_index)); #[cfg(not(target_os = "windows"))]
let res = call_protected(handler_data, || {
assert!( // Leap of faith.
signature.returns().len() <= 1, trampoline(ctx, func, args, rets);
"multi-value returns not yet supported"
);
assert!(
signature.check_param_value_types(params),
"incorrect signature"
);
let param_vec: Vec<u64> = params
.iter()
.map(|val| match val {
Value::I32(x) => *x as u64,
Value::I64(x) => *x as u64,
Value::F32(x) => x.to_bits() as u64,
Value::F64(x) => x.to_bits(),
}) })
.collect(); .is_ok();
let mut return_vec = vec![0; signature.returns().len()]; // the trampoline is called from C on windows
#[cfg(target_os = "windows")]
let res = call_protected(handler_data, trampoline, ctx, func, args, rets).is_ok();
res
}
let trampoline = self let trampoline = self
.trampolines .trampolines
.lookup(sig_index) .lookup(sig_index)
.expect("that trampoline doesn't exist"); .expect("that trampoline doesn't exist");
#[cfg(not(target_os = "windows"))] Some(unsafe {
call_protected(&self.handler_data, || unsafe { Wasm::from_raw_parts(
// Leap of faith. trampoline,
trampoline( invoke,
vmctx_ptr, Some(NonNull::from(&self.handler_data).cast()),
func_ptr,
param_vec.as_ptr(),
return_vec.as_mut_ptr(),
);
})?;
// 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
.iter()
.zip(signature.returns().iter())
.map(|(&x, ty)| match ty {
Type::I32 => Value::I32(x as i32),
Type::I64 => Value::I64(x as i64),
Type::F32 => Value::F32(f32::from_bits(x as u32)),
Type::F64 => Value::F64(f64::from_bits(x as u64)),
})
.collect())
}
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
Box::new(Trapper)
}
}
fn get_func_from_index(
module: &ModuleInner,
import_backing: &ImportBacking,
func_index: FuncIndex,
) -> (*const vm::Func, Context, Arc<FuncSig>, SigIndex) {
let sig_index = *module
.info
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
LocalOrImport::Local(local_func_index) => (
module
.func_resolver
.get(&module, local_func_index)
.expect("broken invariant, func resolver not synced with module.exports")
.cast()
.as_ptr() as *const _,
Context::Internal,
),
LocalOrImport::Import(imported_func_index) => {
let imported_func = import_backing.imported_func(imported_func_index);
(
imported_func.func as *const _,
Context::External(imported_func.vmctx),
) )
} })
}; }
let signature = Arc::clone(&module.info.signatures[sig_index]); unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
(func_ptr, ctx, signature, sig_index) trigger_trap()
}
} }
unsafe impl Send for HandlerData {} unsafe impl Send for HandlerData {}

View File

@ -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())
} }

View File

@ -3,14 +3,10 @@ use crate::signal::HandlerData;
use crate::trampoline::Trampoline; use crate::trampoline::Trampoline;
use std::cell::Cell; use std::cell::Cell;
use std::ffi::c_void; use std::ffi::c_void;
use std::ptr; use std::ptr::{self, NonNull};
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::vm::Func; use wasmer_runtime_core::vm::Func;
use wasmer_runtime_core::{
error::{RuntimeError, RuntimeResult},
structures::TypedIndex,
types::{MemoryIndex, TableIndex},
};
use wasmer_win_exception_handler::CallProtectedData; use wasmer_win_exception_handler::CallProtectedData;
pub use wasmer_win_exception_handler::_call_protected; pub use wasmer_win_exception_handler::_call_protected;
use winapi::shared::minwindef::DWORD; use winapi::shared::minwindef::DWORD;
@ -29,7 +25,7 @@ pub fn call_protected(
handler_data: &HandlerData, handler_data: &HandlerData,
trampoline: Trampoline, trampoline: Trampoline,
ctx: *mut Ctx, ctx: *mut Ctx,
func: *const Func, func: NonNull<Func>,
param_vec: *const u64, param_vec: *const u64,
return_vec: *mut u64, return_vec: *mut u64,
) -> RuntimeResult<()> { ) -> RuntimeResult<()> {
@ -47,8 +43,8 @@ pub fn call_protected(
let CallProtectedData { let CallProtectedData {
code: signum, code: signum,
exceptionAddress: exception_address, exception_address,
instructionPointer: instruction_pointer, instruction_pointer,
} = result.unwrap_err(); } = result.unwrap_err();
if let Some(TrapData { if let Some(TrapData {
@ -57,35 +53,34 @@ pub fn call_protected(
}) = handler_data.lookup(instruction_pointer as _) }) = handler_data.lookup(instruction_pointer as _)
{ {
Err(match signum as DWORD { Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess { EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
memory: MemoryIndex::new(0), msg: "memory out-of-bounds access".into(),
addr: None,
}, },
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode { EXCEPTION_ILLEGAL_INSTRUCTION => 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(),
}, },
}, },
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown { EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap {
msg: "unknown trap".to_string(), msg: "stack overflow trap".into(),
}, },
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation, EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap {
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation, msg: "illegal arithmetic operation".into(),
_ => RuntimeError::Unknown { },
msg: "unknown trap".to_string(), _ => RuntimeError::Trap {
msg: "unknown trap".into(),
}, },
} }
.into()) .into())
@ -103,8 +98,8 @@ pub fn call_protected(
_ => "unkown trapped signal", _ => "unkown trapped signal",
}; };
Err(RuntimeError::Unknown { Err(RuntimeError::Trap {
msg: format!("trap at {} - {}", exception_address, signal), msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
} }
.into()) .into())
} }

View File

@ -6,8 +6,7 @@ use cranelift_codegen::{
isa, Context, isa, Context,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use std::ffi::c_void; use std::{iter, mem, ptr::NonNull};
use std::{iter, mem};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::sys::{Memory, Protect}, backend::sys::{Memory, Protect},
module::{ExportIndex, ModuleInfo}, module::{ExportIndex, ModuleInfo},
@ -23,8 +22,7 @@ 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 = pub type Trampoline = unsafe extern "C" fn(*mut vm::Ctx, NonNull<vm::Func>, *const u64, *mut u64);
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,

View File

@ -1,6 +1,6 @@
[package] [package]
name = "wasmer-emscripten" name = "wasmer-emscripten"
version = "0.1.0" version = "0.3.0"
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,18 +9,26 @@ 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.3.0" }
lazy_static = "1.2.0" lazy_static = "1.2.0"
libc = { git = "https://github.com/rust-lang/libc" } libc = "0.2.49"
byteorder = "1" byteorder = "1"
time = "0.1.41" time = "0.1.41"
wasmer-clif-backend = { path = "../clif-backend", version = "0.3.0" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.3.0", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.3.0", optional = true }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
rand = "0.6" rand = "0.6"
[dev-dependencies] [dev-dependencies]
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.0" }
wabt = "0.7.2" wabt = "0.7.2"
[build-dependencies] [build-dependencies]
glob = "0.2.11" glob = "0.2.11"
[features]
clif = []
llvm = ["wasmer-llvm-backend"]
singlepass = ["wasmer-singlepass-backend"]
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]

View File

@ -46,26 +46,42 @@ pub fn compile(file: &str, ignores: &Vec<String>) -> Option<String> {
output_path.set_extension("js"); output_path.set_extension("js");
let output_str = output_path.to_str().unwrap(); let output_str = output_path.to_str().unwrap();
// Compile to wasm let wasm_file_metadata = {
let _wasm_compilation = Command::new("emcc") let mut wasm_file_path = PathBuf::from(file);
.arg(file) wasm_file_path.set_extension("wasm");
.arg("-s") if let Ok(wasm_file) = File::open(wasm_file_path) {
.arg("WASM=1") Some(wasm_file.metadata().unwrap())
.arg("-o") } else {
.arg(output_str) None
.output() }
.expect("failed to execute process"); };
// panic!("{:?}", wasm_compilation); let real_file = File::open(file).unwrap();
// if output.stderr { let file_metadata = real_file.metadata().unwrap();
// panic!("{}", output.stderr); if wasm_file_metadata.is_none()
// } || file_metadata.modified().unwrap() >= wasm_file_metadata.unwrap().modified().unwrap()
// Remove js file {
// Compile to wasm
let _wasm_compilation = Command::new("emcc")
.arg(file)
.arg("-s")
.arg("WASM=1")
.arg("-o")
.arg(output_str)
.output()
.expect("failed to execute process");
if Path::new(output_str).is_file() { // panic!("{:?}", wasm_compilation);
fs::remove_file(output_str).unwrap(); // if output.stderr {
} else { // panic!("{}", output.stderr);
println!("Output JS not found: {}", output_str); // }
// Remove js file
if Path::new(output_str).is_file() {
fs::remove_file(output_str).unwrap();
} else {
println!("Output JS not found: {}", output_str);
}
} }
let mut output_path = PathBuf::from(file); let mut output_path = PathBuf::from(file);

4
lib/emscripten/emtests/hello.cpp vendored Normal file
View File

@ -0,0 +1,4 @@
#include <iostream>
int main() {
std::cout << "hello world\n";
}

2
lib/emscripten/emtests/hello.out vendored Normal file
View File

@ -0,0 +1,2 @@
hello world

BIN
lib/emscripten/emtests/hello.wasm vendored Normal file

Binary file not shown.

View File

@ -30,16 +30,7 @@ test_i64
test_i64_7z test_i64_7z
test_i64_varargs test_i64_varargs
test_llvm_intrinsics test_llvm_intrinsics
test_longjmp2
test_longjmp3
test_longjmp4
test_longjmp
test_longjmp_exc test_longjmp_exc
test_longjmp_funcptr
test_longjmp_repeat
test_longjmp_stacked
test_longjmp_throw
test_longjmp_unwind
test_lower_intrinsics test_lower_intrinsics
test_main_thread_async_em_asm test_main_thread_async_em_asm
test_mainenv test_mainenv
@ -71,4 +62,47 @@ test_wprintf
test_std_cout_new test_std_cout_new
test_strptime_reentrant test_strptime_reentrant
test_gmtime test_gmtime
test_time_c test_time_c
test_execvp
test_nl_types
test_phiundef
test_pipe
test_printf_2
test_printf_more
test_regex
test_relocatable_void_function
test_rounding
test_set_align
test_sintvars
test_sizeof
test_sscanf
test_sscanf_3
test_sscanf_4
test_sscanf_5
test_sscanf_6
test_sscanf_caps
test_sscanf_float
test_sscanf_n
test_strcasecmp
test_strcmp_uni
test_strndup
test_strstr
test_strtod
test_strtok
test_strtol_bin
test_strtol_dec
test_strtol_hex
test_strtol_oct
test_strtoll_bin
test_strtoll_dec
test_strtoll_hex
test_strtoll_oct
test_struct_varargs
test_transtrcase
test_trickystring
test_unary_literal
test_vfs
test_vprintf
test_vsnprintf
test_write_stdout_fileno
test_zerodiv

17
lib/emscripten/emtests/test_execvp.c vendored Normal file
View 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;
}

View File

@ -0,0 +1 @@
_execvp

BIN
lib/emscripten/emtests/test_execvp.wasm vendored Normal file

Binary file not shown.

View 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;
}

Binary file not shown.

10
lib/emscripten/emtests/test_getcwd.c vendored Normal file
View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include <unistd.h>
int main() {
const unsigned int size = 256;
char cwd[size] = {};
char* buf = getcwd(cwd, size);
printf("getcwd\n");
return 0;
}

View File

@ -0,0 +1 @@
getcwd

BIN
lib/emscripten/emtests/test_getcwd.wasm vendored Normal file

Binary file not shown.

13
lib/emscripten/emtests/test_pipe.c vendored Normal file
View File

@ -0,0 +1,13 @@
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int mypipe[2];
printf("pipe\n");
if (pipe(mypipe)) {
printf("error\n");
}
return 0;
}

1
lib/emscripten/emtests/test_pipe.out vendored Normal file
View File

@ -0,0 +1 @@
pipe

BIN
lib/emscripten/emtests/test_pipe.wasm vendored Normal file

Binary file not shown.

12
lib/emscripten/emtests/test_vfs.c vendored Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
char data[256] = {0};
ssize_t fd = open("data.txt", 0);
ssize_t result = read((int)fd, &data, 255);
printf("content: %s", data);
printf("fd: %zd\n", fd);
return 0;
}

6
lib/emscripten/emtests/test_vfs.md vendored Normal file
View File

@ -0,0 +1,6 @@
The wasm file `test_vfs.wasm` is generated by compiling the `test_vfs.c` and writing a tar.zst blob with a single file
named `data.txt`.
The program expects to find a file named `data.txt` and reads the contents and the file descriptor.
The runtime should mount the virtual filesystem and expose the file.

1
lib/emscripten/emtests/test_vfs.out vendored Normal file
View File

@ -0,0 +1 @@
content: wasmer is awesomer

BIN
lib/emscripten/emtests/test_vfs.wasm vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
wasmer is awesomer

View File

@ -0,0 +1,9 @@
use crate::emscripten_target;
use wasmer_runtime_core::vm::Ctx;
///emscripten: _llvm_bswap_i64
pub fn _llvm_bswap_i64(_ctx: &mut Ctx, _low: i32, high: i32) -> i32 {
debug!("emscripten::_llvm_bswap_i64");
emscripten_target::setTempRet0(_ctx, _low.swap_bytes());
high.swap_bytes()
}

View File

@ -1,265 +1,267 @@
#![allow(non_snake_case)]
use crate::env::get_emscripten_data; use crate::env::get_emscripten_data;
#[cfg(target_os = "linux")]
use libc::getdtablesize;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
pub fn setTempRet0(ctx: &mut Ctx, a: i32) { pub fn setTempRet0(ctx: &mut Ctx, val: i32) {
debug!("emscripten::setTempRet0"); debug!("emscripten::setTempRet0: {}", val);
get_emscripten_data(ctx).temp_ret_0 = val;
} }
pub fn getTempRet0(ctx: &mut Ctx) -> i32 { pub fn getTempRet0(ctx: &mut Ctx) -> i32 {
debug!("emscripten::getTempRet0"); debug!("emscripten::getTempRet0");
0 get_emscripten_data(ctx).temp_ret_0
} }
pub fn nullFunc_ji(ctx: &mut Ctx, a: i32) {
debug!("emscripten::nullFunc_ji"); pub fn __Unwind_Backtrace(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
}
pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 {
debug!("emscripten::invoke_i");
if let Some(dyn_call_i) = &get_emscripten_data(ctx).dyn_call_i {
dyn_call_i.call(index).unwrap()
} else {
panic!("dyn_call_i is set to None");
}
}
pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
debug!("emscripten::invoke_ii");
if let Some(dyn_call_ii) = &get_emscripten_data(ctx).dyn_call_ii {
dyn_call_ii.call(index, a1).unwrap()
} else {
panic!("dyn_call_ii is set to None");
}
}
pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::invoke_iii");
if let Some(dyn_call_iii) = &get_emscripten_data(ctx).dyn_call_iii {
dyn_call_iii.call(index, a1, a2).unwrap()
} else {
panic!("dyn_call_iii is set to None");
}
}
pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iiii");
if let Some(dyn_call_iiii) = &get_emscripten_data(ctx).dyn_call_iiii {
dyn_call_iiii.call(index, a1, a2, a3).unwrap()
} else {
panic!("dyn_call_iiii is set to None");
}
}
pub fn invoke_v(ctx: &mut Ctx, index: i32) {
debug!("emscripten::invoke_v");
if let Some(dyn_call_v) = &get_emscripten_data(ctx).dyn_call_v {
dyn_call_v.call(index).unwrap();
} else {
panic!("dyn_call_v is set to None");
}
}
pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) {
debug!("emscripten::invoke_vi");
if let Some(dyn_call_vi) = &get_emscripten_data(ctx).dyn_call_vi {
dyn_call_vi.call(index, a1).unwrap();
} else {
panic!("dyn_call_vi is set to None");
}
}
pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
debug!("emscripten::invoke_vii");
if let Some(dyn_call_vii) = &get_emscripten_data(ctx).dyn_call_vii {
dyn_call_vii.call(index, a1, a2).unwrap();
} else {
panic!("dyn_call_vii is set to None");
}
}
pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_viii");
if let Some(dyn_call_viii) = &get_emscripten_data(ctx).dyn_call_viii {
dyn_call_viii.call(index, a1, a2, a3).unwrap();
} else {
panic!("dyn_call_viii is set to None");
}
}
pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viiii");
if let Some(dyn_call_viiii) = &get_emscripten_data(ctx).dyn_call_viiii {
dyn_call_viiii.call(index, a1, a2, a3, a4).unwrap();
} else {
panic!("dyn_call_viiii is set to None");
}
}
pub fn __Unwind_Backtrace(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
debug!("emscripten::__Unwind_Backtrace"); debug!("emscripten::__Unwind_Backtrace");
0 0
} }
pub fn __Unwind_FindEnclosingFunction(ctx: &mut Ctx, a: i32) -> i32 { pub fn __Unwind_FindEnclosingFunction(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::__Unwind_FindEnclosingFunction"); debug!("emscripten::__Unwind_FindEnclosingFunction");
0 0
} }
pub fn __Unwind_GetIPInfo(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn __Unwind_GetIPInfo(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::__Unwind_GetIPInfo"); debug!("emscripten::__Unwind_GetIPInfo");
0 0
} }
pub fn ___cxa_find_matching_catch_2(ctx: &mut Ctx) -> i32 { pub fn ___cxa_find_matching_catch_2(_ctx: &mut Ctx) -> i32 {
debug!("emscripten::___cxa_find_matching_catch_2"); debug!("emscripten::___cxa_find_matching_catch_2");
0 0
} }
pub fn ___cxa_find_matching_catch_3(ctx: &mut Ctx, a: i32) -> i32 { pub fn ___cxa_find_matching_catch_3(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::___cxa_find_matching_catch_3"); debug!("emscripten::___cxa_find_matching_catch_3");
0 0
} }
pub fn ___cxa_free_exception(ctx: &mut Ctx, a: i32) { pub fn ___cxa_free_exception(_ctx: &mut Ctx, _a: i32) {
debug!("emscripten::___cxa_free_exception"); debug!("emscripten::___cxa_free_exception");
} }
pub fn ___resumeException(ctx: &mut Ctx, a: i32) { pub fn ___resumeException(_ctx: &mut Ctx, _a: i32) {
debug!("emscripten::___resumeException"); debug!("emscripten::___resumeException");
} }
pub fn _dladdr(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn _dladdr(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_dladdr"); debug!("emscripten::_dladdr");
0 0
} }
pub fn _pthread_cond_destroy(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_cond_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_cond_destroy"); debug!("emscripten::_pthread_cond_destroy");
0 0
} }
pub fn _pthread_cond_init(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn _pthread_getspecific(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_getspecific");
0
}
pub fn _pthread_setspecific(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_setspecific");
0
}
pub fn _pthread_once(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_once");
0
}
pub fn _pthread_key_create(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_key_create");
0
}
pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
debug!("emscripten::_pthread_create");
0
}
pub fn _pthread_join(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_join");
0
}
pub fn _pthread_cond_init(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_cond_init"); debug!("emscripten::_pthread_cond_init");
0 0
} }
pub fn _pthread_cond_signal(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_cond_signal(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_cond_signal"); debug!("emscripten::_pthread_cond_signal");
0 0
} }
pub fn _pthread_cond_wait(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn _pthread_cond_wait(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_cond_wait"); debug!("emscripten::_pthread_cond_wait");
0 0
} }
pub fn _pthread_condattr_destroy(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_condattr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_condattr_destroy"); debug!("emscripten::_pthread_condattr_destroy");
0 0
} }
pub fn _pthread_condattr_init(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_condattr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_condattr_init"); debug!("emscripten::_pthread_condattr_init");
0 0
} }
pub fn _pthread_condattr_setclock(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn _pthread_condattr_setclock(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_condattr_setclock"); debug!("emscripten::_pthread_condattr_setclock");
0 0
} }
pub fn _pthread_mutex_destroy(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_mutex_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_mutex_destroy"); debug!("emscripten::_pthread_mutex_destroy");
0 0
} }
pub fn _pthread_mutex_init(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn _pthread_mutex_init(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_mutex_init"); debug!("emscripten::_pthread_mutex_init");
0 0
} }
pub fn _pthread_mutexattr_destroy(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_mutexattr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_mutexattr_destroy"); debug!("emscripten::_pthread_mutexattr_destroy");
0 0
} }
pub fn _pthread_mutexattr_init(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_mutexattr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_mutexattr_init"); debug!("emscripten::_pthread_mutexattr_init");
0 0
} }
pub fn _pthread_mutexattr_settype(ctx: &mut Ctx, a: i32, b: i32) -> i32 { pub fn _pthread_mutexattr_settype(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_mutexattr_settype"); debug!("emscripten::_pthread_mutexattr_settype");
0 0
} }
pub fn _pthread_rwlock_rdlock(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_rwlock_rdlock(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_rwlock_rdlock"); debug!("emscripten::_pthread_rwlock_rdlock");
0 0
} }
pub fn _pthread_rwlock_unlock(ctx: &mut Ctx, a: i32) -> i32 { pub fn _pthread_rwlock_unlock(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_rwlock_unlock"); debug!("emscripten::_pthread_rwlock_unlock");
0 0
} }
pub fn ___gxx_personality_v0(ctx: &mut Ctx, a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) -> i32 { pub fn _pthread_setcancelstate(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
debug!("emscripten::_pthread_setcancelstate");
0
}
pub fn ___gxx_personality_v0(
_ctx: &mut Ctx,
_a: i32,
_b: i32,
_c: i32,
_d: i32,
_e: i32,
_f: i32,
) -> i32 {
debug!("emscripten::___gxx_personality_v0"); debug!("emscripten::___gxx_personality_v0");
0 0
} }
// round 2 #[cfg(target_os = "linux")]
pub fn nullFunc_dii(ctx: &mut Ctx, index: i32) { pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 {
debug!("emscripten::nullFunc_dii"); debug!("emscripten::getdtablesize");
unsafe { getdtablesize() }
} }
pub fn nullFunc_diiii(ctx: &mut Ctx, index: i32) { #[cfg(not(target_os = "linux"))]
debug!("emscripten::nullFunc_diiii"); pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 {
debug!("emscripten::getdtablesize");
-1
} }
pub fn nullFunc_iiji(ctx: &mut Ctx, index: i32) { pub fn _gethostbyaddr(_ctx: &mut Ctx, _addr: i32, _addrlen: i32, _atype: i32) -> i32 {
debug!("emscripten::nullFunc_iiji"); debug!("emscripten::gethostbyaddr");
0
} }
pub fn nullFunc_j(ctx: &mut Ctx, index: i32) { pub fn _gethostbyname_r(
debug!("emscripten::nullFunc_j"); _ctx: &mut Ctx,
_name: i32,
_ret: i32,
_buf: i32,
_buflen: i32,
_out: i32,
_err: i32,
) -> i32 {
debug!("emscripten::gethostbyname_r");
0
} }
pub fn nullFunc_jij(ctx: &mut Ctx, index: i32) { // NOTE: php.js has proper impl; libc has proper impl for linux
debug!("emscripten::nullFunc_jij"); pub fn _getloadavg(_ctx: &mut Ctx, _loadavg: i32, _nelem: i32) -> i32 {
debug!("emscripten::getloadavg");
0
} }
pub fn nullFunc_jjj(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_jjj"); // Invoke functions
// They save the stack to allow unwinding
// Macro definitions
macro_rules! invoke {
($ctx: ident, $name:ident, $( $arg:ident ),*) => {{
let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
match result {
Ok(v) => v,
Err(_e) => {
get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
// TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error
// JS version is: if (e !== e+0 && e !== 'longjmp') throw e;
get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
0 as _
}
}
}};
} }
pub fn nullFunc_vd(ctx: &mut Ctx, index: i32) { macro_rules! invoke_no_return {
debug!("emscripten::nullFunc_vd"); ($ctx: ident, $name:ident, $( $arg:ident ),*) => {{
let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
match result {
Ok(v) => v,
Err(_e) => {
get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
// TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error
// JS version is: if (e !== e+0 && e !== 'longjmp') throw e;
get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
}
}
}};
} }
pub fn nullFunc_viiiiiii(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_viiiiiii"); // Invoke functions
pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 {
debug!("emscripten::invoke_i");
invoke!(ctx, dyn_call_i, index)
} }
pub fn nullFunc_viiiiiiii(ctx: &mut Ctx, index: i32) { pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
debug!("emscripten::nullFunc_viiiiiiii"); debug!("emscripten::invoke_ii");
invoke!(ctx, dyn_call_ii, index, a1)
} }
pub fn nullFunc_viiiiiiiii(ctx: &mut Ctx, index: i32) { pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::nullFunc_viiiiiiiii"); debug!("emscripten::invoke_iii");
invoke!(ctx, dyn_call_iii, index, a1, a2)
} }
pub fn nullFunc_viiij(ctx: &mut Ctx, index: i32) { pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::nullFunc_viiij"); debug!("emscripten::invoke_iiii");
invoke!(ctx, dyn_call_iiii, index, a1, a2, a3)
} }
pub fn nullFunc_viiijiiii(ctx: &mut Ctx, index: i32) { pub fn invoke_iifi(ctx: &mut Ctx, index: i32, a1: i32, a2: f64, a3: i32) -> i32 {
debug!("emscripten::nullFunc_viiijiiii"); debug!("emscripten::invoke_iifi");
invoke!(ctx, dyn_call_iifi, index, a1, a2, a3)
} }
pub fn nullFunc_viiijiiiiii(ctx: &mut Ctx, index: i32) { pub fn invoke_v(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_viiijiiiiii"); debug!("emscripten::invoke_v");
invoke_no_return!(ctx, dyn_call_v, index);
} }
pub fn nullFunc_viij(ctx: &mut Ctx, index: i32) { pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) {
debug!("emscripten::nullFunc_viij"); debug!("emscripten::invoke_vi");
invoke_no_return!(ctx, dyn_call_vi, index, a1);
} }
pub fn nullFunc_viiji(ctx: &mut Ctx, index: i32) { pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
debug!("emscripten::nullFunc_viiji"); debug!("emscripten::invoke_vii");
invoke_no_return!(ctx, dyn_call_vii, index, a1, a2);
} }
pub fn nullFunc_viijiii(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_viijiii"); pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_viii");
invoke_no_return!(ctx, dyn_call_viii, index, a1, a2, a3);
} }
pub fn nullFunc_viijj(ctx: &mut Ctx, index: i32) { pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::nullFunc_viijj"); debug!("emscripten::invoke_viiii");
} invoke_no_return!(ctx, dyn_call_viiii, index, a1, a2, a3, a4);
pub fn nullFunc_vij(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_vij");
}
pub fn nullFunc_viji(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_viji");
}
pub fn nullFunc_vijiii(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_vijiii");
}
pub fn nullFunc_vijj(ctx: &mut Ctx, index: i32) {
debug!("emscripten::nullFunc_vijj");
} }
pub fn invoke_dii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> f64 { pub fn invoke_dii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> f64 {
debug!("emscripten::invoke_dii"); debug!("emscripten::invoke_dii");
if let Some(dyn_call_dii) = &get_emscripten_data(ctx).dyn_call_dii { invoke!(ctx, dyn_call_dii, index, a1, a2)
dyn_call_dii.call(index, a1, a2).unwrap()
} else {
panic!("dyn_call_dii is set to None");
}
} }
pub fn invoke_diiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 { pub fn invoke_diiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 {
debug!("emscripten::invoke_diiii"); debug!("emscripten::invoke_diiii");
if let Some(dyn_call_diiii) = &get_emscripten_data(ctx).dyn_call_diiii { invoke!(ctx, dyn_call_diiii, index, a1, a2, a3, a4)
dyn_call_diiii.call(index, a1, a2, a3, a4).unwrap()
} else {
panic!("dyn_call_diiii is set to None");
}
} }
pub fn invoke_iiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 { pub fn invoke_iiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_iiiii"); debug!("emscripten::invoke_iiiii");
if let Some(dyn_call_iiiii) = &get_emscripten_data(ctx).dyn_call_iiiii { invoke!(ctx, dyn_call_iiiii, index, a1, a2, a3, a4)
dyn_call_iiiii.call(index, a1, a2, a3, a4).unwrap()
} else {
panic!("dyn_call_iiiii is set to None");
}
} }
pub fn invoke_iiiiii( pub fn invoke_iiiiii(
ctx: &mut Ctx, ctx: &mut Ctx,
@ -271,27 +273,129 @@ pub fn invoke_iiiiii(
a5: i32, a5: i32,
) -> i32 { ) -> i32 {
debug!("emscripten::invoke_iiiiii"); debug!("emscripten::invoke_iiiiii");
if let Some(dyn_call_iiiiii) = &get_emscripten_data(ctx).dyn_call_iiiiii { invoke!(ctx, dyn_call_iiiiii, index, a1, a2, a3, a4, a5)
dyn_call_iiiiii.call(index, a1, a2, a3, a4, a5).unwrap() }
} else { pub fn invoke_iiiiiii(
panic!("dyn_call_iiiiii is set to None"); ctx: &mut Ctx,
} index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiii");
invoke!(ctx, dyn_call_iiiiiii, index, a1, a2, a3, a4, a5, a6)
}
pub fn invoke_iiiiiiii(
ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
a7: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiiii");
invoke!(ctx, dyn_call_iiiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
}
pub fn invoke_iiiiiiiii(
ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
a7: i32,
a8: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiiiii");
invoke!(
ctx,
dyn_call_iiiiiiiii,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8
)
}
pub fn invoke_iiiiiiiiii(
ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
a7: i32,
a8: i32,
a9: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiiiiii");
invoke!(
ctx,
dyn_call_iiiiiiiiii,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9
)
}
pub fn invoke_iiiiiiiiiii(
ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
a7: i32,
a8: i32,
a9: i32,
a10: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiiiiiii");
invoke!(
ctx,
dyn_call_iiiiiiiiiii,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10
)
} }
pub fn invoke_vd(ctx: &mut Ctx, index: i32, a1: f64) { pub fn invoke_vd(ctx: &mut Ctx, index: i32, a1: f64) {
debug!("emscripten::invoke_vd"); debug!("emscripten::invoke_vd");
if let Some(dyn_call_vd) = &get_emscripten_data(ctx).dyn_call_vd { invoke_no_return!(ctx, dyn_call_vd, index, a1)
dyn_call_vd.call(index, a1).unwrap();
} else {
panic!("dyn_call_vd is set to None");
}
} }
pub fn invoke_viiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) { pub fn invoke_viiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiiii"); debug!("emscripten::invoke_viiiii");
if let Some(dyn_call_viiiii) = &get_emscripten_data(ctx).dyn_call_viiiii { invoke_no_return!(ctx, dyn_call_viiiii, index, a1, a2, a3, a4, a5)
dyn_call_viiiii.call(index, a1, a2, a3, a4, a5).unwrap();
} else {
panic!("dyn_call_viiiii is set to None");
}
} }
pub fn invoke_viiiiii( pub fn invoke_viiiiii(
ctx: &mut Ctx, ctx: &mut Ctx,
@ -304,13 +408,7 @@ pub fn invoke_viiiiii(
a6: i32, a6: i32,
) { ) {
debug!("emscripten::invoke_viiiiii"); debug!("emscripten::invoke_viiiiii");
if let Some(dyn_call_viiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiii { invoke_no_return!(ctx, dyn_call_viiiiii, index, a1, a2, a3, a4, a5, a6)
dyn_call_viiiiii
.call(index, a1, a2, a3, a4, a5, a6)
.unwrap();
} else {
panic!("dyn_call_viiiiii is set to None");
}
} }
pub fn invoke_viiiiiii( pub fn invoke_viiiiiii(
ctx: &mut Ctx, ctx: &mut Ctx,
@ -324,13 +422,7 @@ pub fn invoke_viiiiiii(
a7: i32, a7: i32,
) { ) {
debug!("emscripten::invoke_viiiiiii"); debug!("emscripten::invoke_viiiiiii");
if let Some(dyn_call_viiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiii { invoke_no_return!(ctx, dyn_call_viiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
dyn_call_viiiiiii
.call(index, a1, a2, a3, a4, a5, a6, a7)
.unwrap();
} else {
panic!("dyn_call_viiiiiii is set to None");
}
} }
pub fn invoke_viiiiiiii( pub fn invoke_viiiiiiii(
ctx: &mut Ctx, ctx: &mut Ctx,
@ -345,13 +437,19 @@ pub fn invoke_viiiiiiii(
a8: i32, a8: i32,
) { ) {
debug!("emscripten::invoke_viiiiiiii"); debug!("emscripten::invoke_viiiiiiii");
if let Some(dyn_call_viiiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiiii { invoke_no_return!(
dyn_call_viiiiiiii ctx,
.call(index, a1, a2, a3, a4, a5, a6, a7, a8) dyn_call_viiiiiiii,
.unwrap(); index,
} else { a1,
panic!("dyn_call_viiiiiiii is set to None"); a2,
} a3,
a4,
a5,
a6,
a7,
a8
)
} }
pub fn invoke_viiiiiiiii( pub fn invoke_viiiiiiiii(
ctx: &mut Ctx, ctx: &mut Ctx,
@ -367,21 +465,75 @@ pub fn invoke_viiiiiiiii(
a9: i32, a9: i32,
) { ) {
debug!("emscripten::invoke_viiiiiiiii"); debug!("emscripten::invoke_viiiiiiiii");
if let Some(dyn_call_viiiiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiiiii { invoke_no_return!(
dyn_call_viiiiiiiii ctx,
.call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9) dyn_call_viiiiiiiii,
.unwrap(); index,
} else { a1,
panic!("dyn_call_viiiiiiiii is set to None"); a2,
} a3,
a4,
a5,
a6,
a7,
a8,
a9
)
} }
pub fn invoke_viiiiiiiiii(
ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
a7: i32,
a8: i32,
a9: i32,
a10: i32,
) {
debug!("emscripten::invoke_viiiiiiiiii");
invoke_no_return!(
ctx,
dyn_call_viiiiiiiiii,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10
)
}
pub fn invoke_iij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iij");
invoke!(ctx, dyn_call_iij, index, a1, a2, a3)
}
pub fn invoke_iiji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 { pub fn invoke_iiji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_iiji"); debug!("emscripten::invoke_iiji");
if let Some(dyn_call_iiji) = &get_emscripten_data(ctx).dyn_call_iiji { invoke!(ctx, dyn_call_iiji, index, a1, a2, a3, a4)
dyn_call_iiji.call(index, a1, a2, a3, a4).unwrap() }
} else {
panic!("dyn_call_iiji is set to None"); pub fn invoke_iiijj(
} ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: i32,
a4: i32,
a5: i32,
a6: i32,
) -> i32 {
debug!("emscripten::invoke_iiijj");
invoke!(ctx, dyn_call_iiijj, index, a1, a2, a3, a4, a5, a6)
} }
pub fn invoke_j(ctx: &mut Ctx, index: i32) -> i32 { pub fn invoke_j(ctx: &mut Ctx, index: i32) -> i32 {
debug!("emscripten::invoke_j"); debug!("emscripten::invoke_j");
@ -399,6 +551,15 @@ pub fn invoke_ji(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
panic!("dyn_call_ji is set to None"); panic!("dyn_call_ji is set to None");
} }
} }
pub fn invoke_jii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::invoke_jii");
if let Some(dyn_call_jii) = &get_emscripten_data(ctx).dyn_call_jii {
dyn_call_jii.call(index, a1, a2).unwrap()
} else {
panic!("dyn_call_jii is set to None");
}
}
pub fn invoke_jij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 { pub fn invoke_jij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_jij"); debug!("emscripten::invoke_jij");
if let Some(dyn_call_jij) = &get_emscripten_data(ctx).dyn_call_jij { if let Some(dyn_call_jij) = &get_emscripten_data(ctx).dyn_call_jij {
@ -522,6 +683,14 @@ pub fn invoke_viijj(
panic!("dyn_call_viijj is set to None"); panic!("dyn_call_viijj is set to None");
} }
} }
pub fn invoke_vj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
debug!("emscripten::invoke_vj");
if let Some(dyn_call_vj) = &get_emscripten_data(ctx).dyn_call_vj {
dyn_call_vj.call(index, a1, a2).unwrap();
} else {
panic!("dyn_call_vj is set to None");
}
}
pub fn invoke_vij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) { pub fn invoke_vij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_vij"); debug!("emscripten::invoke_vij");
if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij { if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij {
@ -563,3 +732,42 @@ pub fn invoke_vijj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32
panic!("dyn_call_vijj is set to None"); panic!("dyn_call_vijj is set to None");
} }
} }
pub fn invoke_viid(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: f64) {
debug!("emscripten::invoke_viid");
invoke_no_return!(ctx, dyn_call_viid, index, a1, a2, a3);
}
pub fn invoke_viidii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: f64, a4: i32, a5: i32) {
debug!("emscripten::invoke_viidii");
invoke_no_return!(ctx, dyn_call_viidii, index, a1, a2, a3, a4, a5);
}
pub fn invoke_viidddddddd(
ctx: &mut Ctx,
index: i32,
a1: i32,
a2: i32,
a3: f64,
a4: f64,
a5: f64,
a6: f64,
a7: f64,
a8: f64,
a9: f64,
a10: f64,
) {
debug!("emscripten::invoke_viidddddddd");
invoke_no_return!(
ctx,
dyn_call_viidddddddd,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10
);
}

View File

@ -47,6 +47,13 @@ pub fn _getpagesize(_ctx: &mut Ctx) -> u32 {
16384 16384
} }
pub fn _times(ctx: &mut Ctx, buffer: u32) -> u32 {
if buffer != 0 {
call_memset(ctx, buffer, 0, 16);
}
0
}
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) { pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
debug!("emscripten::___build_environment {}", environ); debug!("emscripten::___build_environment {}", environ);
@ -70,8 +77,8 @@ pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
// }; // };
} }
pub fn ___assert_fail(_ctx: &mut Ctx, a: c_int, b: c_int, c: c_int, d: c_int) { pub fn ___assert_fail(_ctx: &mut Ctx, _a: c_int, _b: c_int, _c: c_int, _d: c_int) {
debug!("emscripten::___assert_fail {} {} {} {}", a, b, c, d); debug!("emscripten::___assert_fail {} {} {} {}", _a, _b, _c, _d);
// TODO: Implement like emscripten expects regarding memory/page size // TODO: Implement like emscripten expects regarding memory/page size
// TODO raise an error // TODO raise an error
} }

View File

@ -66,6 +66,8 @@ pub fn _unsetenv(ctx: &mut Ctx, name: c_int) -> c_int {
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int { pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr); debug!("emscripten::_getpwnam {}", name_ptr);
#[cfg(feature = "debug")]
let _ = name_ptr;
#[repr(C)] #[repr(C)]
struct GuestPasswd { struct GuestPasswd {

View File

@ -7,7 +7,6 @@ use std::os::raw::c_char;
use crate::env::call_malloc; use crate::env::call_malloc;
use crate::utils::{copy_cstr_into_wasm, read_string_from_wasm}; use crate::utils::{copy_cstr_into_wasm, read_string_from_wasm};
use std::ffi::CStr;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
extern "C" { extern "C" {
@ -29,10 +28,8 @@ pub fn _getenv(ctx: &mut Ctx, name: u32) -> u32 {
} }
/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int); /// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int);
pub fn _setenv(ctx: &mut Ctx, name: u32, value: u32, overwrite: u32) -> c_int { pub fn _setenv(ctx: &mut Ctx, name: u32, value: u32, _overwrite: u32) -> c_int {
debug!("emscripten::_setenv"); debug!("emscripten::_setenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name);
let value_addr = emscripten_memory_pointer!(ctx.memory(0), value);
// setenv does not exist on windows, so we hack it with _putenv // setenv does not exist on windows, so we hack it with _putenv
let name = read_string_from_wasm(ctx.memory(0), name); let name = read_string_from_wasm(ctx.memory(0), name);
let value = read_string_from_wasm(ctx.memory(0), value); let value = read_string_from_wasm(ctx.memory(0), value);
@ -47,17 +44,16 @@ pub fn _setenv(ctx: &mut Ctx, name: u32, value: u32, overwrite: u32) -> c_int {
/// emscripten: _putenv // (name: *const char); /// emscripten: _putenv // (name: *const char);
pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int { pub fn _putenv(ctx: &mut Ctx, name: c_int) -> c_int {
debug!("emscripten::_putenv"); debug!("emscripten::_putenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char;
debug!("=> name({:?})", unsafe {
debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); std::ffi::CStr::from_ptr(name_addr)
});
unsafe { putenv(name_addr) } unsafe { putenv(name_addr) }
} }
/// emscripten: _unsetenv // (name: *const char); /// emscripten: _unsetenv // (name: *const char);
pub fn _unsetenv(ctx: &mut Ctx, name: u32) -> c_int { pub fn _unsetenv(ctx: &mut Ctx, name: u32) -> c_int {
debug!("emscripten::_unsetenv"); debug!("emscripten::_unsetenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name);
let name = read_string_from_wasm(ctx.memory(0), name); let name = read_string_from_wasm(ctx.memory(0), name);
// no unsetenv on windows, so use putenv with an empty value // no unsetenv on windows, so use putenv with an empty value
let unsetenv_string = format!("{}=", name); let unsetenv_string = format!("{}=", name);
@ -70,6 +66,8 @@ pub fn _unsetenv(ctx: &mut Ctx, name: u32) -> c_int {
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int { pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr); debug!("emscripten::_getpwnam {}", name_ptr);
#[cfg(not(feature = "debug"))]
let _ = name_ptr;
#[repr(C)] #[repr(C)]
struct GuestPasswd { struct GuestPasswd {
@ -102,6 +100,8 @@ pub fn _getpwnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int { pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
debug!("emscripten::_getgrnam {}", name_ptr); debug!("emscripten::_getgrnam {}", name_ptr);
#[cfg(not(feature = "debug"))]
let _ = name_ptr;
#[repr(C)] #[repr(C)]
struct GuestGroup { struct GuestGroup {
@ -126,6 +126,8 @@ pub fn _getgrnam(ctx: &mut Ctx, name_ptr: c_int) -> c_int {
pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long { pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long {
debug!("emscripten::_sysconf {}", name); debug!("emscripten::_sysconf {}", name);
#[cfg(not(feature = "debug"))]
let _ = name;
// stub because sysconf is not valid on windows // stub because sysconf is not valid on windows
0 0
} }

View File

@ -1,8 +1,8 @@
// use std::collections::HashMap; // use std::collections::HashMap;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
pub fn ___seterrno(_ctx: &mut Ctx, value: i32) { pub fn ___seterrno(_ctx: &mut Ctx, _value: i32) {
debug!("emscripten::___seterrno {}", value); debug!("emscripten::___seterrno {}", _value);
// TODO: Incomplete impl // TODO: Incomplete impl
eprintln!("failed to set errno!"); eprintln!("failed to set errno!");
// value // value

View File

@ -14,3 +14,17 @@ pub fn ___cxa_throw(ctx: &mut Ctx, _ptr: u32, _ty: u32, _destructor: u32) {
debug!("emscripten::___cxa_throw"); debug!("emscripten::___cxa_throw");
_abort(ctx); _abort(ctx);
} }
pub fn ___cxa_begin_catch(_ctx: &mut Ctx, _exception_object_ptr: u32) -> i32 {
debug!("emscripten::___cxa_begin_catch");
-1
}
pub fn ___cxa_end_catch(_ctx: &mut Ctx) {
debug!("emscripten::___cxa_end_catch");
}
pub fn ___cxa_uncaught_exception(_ctx: &mut Ctx) -> i32 {
debug!("emscripten::___cxa_uncaught_exception");
-1
}

View File

@ -0,0 +1,53 @@
use crate::varargs::VarArgs;
use libc::execvp as libc_execvp;
use std::cell::Cell;
use std::ffi::CString;
use wasmer_runtime_core::vm::Ctx;
pub fn execvp(ctx: &mut Ctx, command_name_offset: u32, argv_offset: u32) -> i32 {
// a single reference to re-use
let emscripten_memory = ctx.memory(0);
// read command name as string
let command_name_string_vec: Vec<u8> = emscripten_memory.view()
[(command_name_offset as usize)..]
.iter()
.map(|cell| cell.get())
.take_while(|&byte| byte != 0)
.collect();
let command_name_string = CString::new(command_name_string_vec).unwrap();
// get the array of args
let mut argv: Vec<*const i8> = emscripten_memory.view()[((argv_offset / 4) as usize)..]
.iter()
.map(|cell: &Cell<u32>| cell.get())
.take_while(|&byte| byte != 0)
.map(|offset| {
let p: *const i8 = (emscripten_memory.view::<u8>()[(offset as usize)..])
.iter()
.map(|cell| cell.as_ptr() as *const i8)
.collect::<Vec<*const i8>>()[0];
p
})
.collect();
// push a nullptr on to the end of the args array
argv.push(std::ptr::null());
// construct raw pointers and hand them to `execvp`
let command_pointer = command_name_string.as_ptr() as *const i8;
let args_pointer = argv.as_ptr();
unsafe { libc_execvp(command_pointer, args_pointer) }
}
/// execl
pub fn execl(_ctx: &mut Ctx, _path_ptr: i32, _arg0_ptr: i32, _varargs: VarArgs) -> i32 {
debug!("emscripten::execl");
-1
}
/// execle
pub fn execle(_ctx: &mut Ctx, _path_ptr: i32, _arg0_ptr: i32, _varargs: VarArgs) -> i32 {
debug!("emscripten::execle");
-1
}

View File

@ -0,0 +1,7 @@
use wasmer_runtime_core::vm::Ctx;
// __exit
pub fn exit(_ctx: &mut Ctx, value: i32) {
debug!("emscripten::exit {}", value);
::std::process::exit(value);
}

View File

@ -9,3 +9,55 @@ pub use self::unix::*;
#[cfg(windows)] #[cfg(windows)]
pub use self::windows::*; pub use self::windows::*;
use wasmer_runtime_core::vm::Ctx;
/// getprotobyname
pub fn getprotobyname(_ctx: &mut Ctx, _name_ptr: i32) -> i32 {
debug!("emscripten::getprotobyname");
unimplemented!()
}
/// getprotobynumber
pub fn getprotobynumber(_ctx: &mut Ctx, _one: i32) -> i32 {
debug!("emscripten::getprotobynumber");
unimplemented!()
}
/// sigdelset
pub fn sigdelset(ctx: &mut Ctx, set: i32, signum: i32) -> i32 {
debug!("emscripten::sigdelset");
let memory = ctx.memory(0);
#[allow(clippy::cast_ptr_alignment)]
let ptr = emscripten_memory_pointer!(memory, set) as *mut i32;
unsafe { *ptr = *ptr & !(1 << (signum - 1)) }
0
}
/// sigfillset
pub fn sigfillset(ctx: &mut Ctx, set: i32) -> i32 {
debug!("emscripten::sigfillset");
let memory = ctx.memory(0);
#[allow(clippy::cast_ptr_alignment)]
let ptr = emscripten_memory_pointer!(memory, set) as *mut i32;
unsafe {
*ptr = -1;
}
0
}
/// tzset
pub fn tzset(_ctx: &mut Ctx) {
debug!("emscripten::tzset - stub");
//unimplemented!()
}
/// strptime
pub fn strptime(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::strptime");
unimplemented!()
}

View File

@ -1,9 +1,9 @@
use libc::printf as _printf; use libc::{chroot as _chroot, printf as _printf};
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// putchar /// putchar
pub fn putchar(ctx: &mut Ctx, chr: i32) { pub fn putchar(_ctx: &mut Ctx, chr: i32) {
unsafe { libc::putchar(chr) }; unsafe { libc::putchar(chr) };
} }
@ -15,3 +15,16 @@ pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
_printf(addr, extra) _printf(addr, extra)
} }
} }
/// chroot
pub fn chroot(ctx: &mut Ctx, name_ptr: i32) -> i32 {
debug!("emscripten::chroot");
let name = emscripten_memory_pointer!(ctx.memory(0), name_ptr) as *const i8;
unsafe { _chroot(name) }
}
/// getpwuid
pub fn getpwuid(_ctx: &mut Ctx, _uid: i32) -> i32 {
debug!("emscripten::getpwuid");
0
}

View File

@ -1,4 +1,3 @@
use libc::{c_char, c_int};
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
// This may be problematic for msvc which uses inline functions for the printf family // This may be problematic for msvc which uses inline functions for the printf family
@ -15,16 +14,33 @@ use wasmer_runtime_core::vm::Ctx;
//} //}
/// putchar /// putchar
pub fn putchar(ctx: &mut Ctx, chr: i32) { pub fn putchar(_ctx: &mut Ctx, chr: i32) {
unsafe { libc::putchar(chr) }; unsafe { libc::putchar(chr) };
} }
/// printf /// printf
pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 { pub fn printf(_ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
debug!("emscripten::printf {}, {}", memory_offset, extra); debug!("emscripten::printf {}, {}", memory_offset, extra);
#[cfg(not(feature = "debug"))]
{
let _ = memory_offset;
let _ = extra;
}
// unsafe { // unsafe {
// let addr = emscripten_memory_pointer!(ctx.memory(0), memory_offset) as _; // let addr = emscripten_memory_pointer!(ctx.memory(0), memory_offset) as _;
// _printf(addr, extra) // _printf(addr, extra)
// } // }
-1 -1
} }
/// chroot
pub fn chroot(_ctx: &mut Ctx, _name_ptr: i32) -> i32 {
debug!("emscripten::chroot");
unimplemented!()
}
/// getpwuid
pub fn getpwuid(_ctx: &mut Ctx, _uid: i32) -> i32 {
debug!("emscripten::getpwuid");
unimplemented!()
}

View File

@ -1,43 +1,61 @@
use super::env::get_emscripten_data; use super::env::get_emscripten_data;
use libc::{c_int, c_void}; use super::process::abort_with_message;
use std::cell::UnsafeCell; use libc::c_int;
// use std::cell::UnsafeCell;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
/// setjmp /// setjmp
pub fn __setjmp(ctx: &mut Ctx, env_addr: u32) -> c_int { pub fn __setjmp(ctx: &mut Ctx, _env_addr: u32) -> c_int {
debug!("emscripten::__setjmp (setjmp)"); debug!("emscripten::__setjmp (setjmp)");
unsafe { abort_with_message(ctx, "missing function: _longjmp");
// Rather than using the env as the holder of the jump buffer pointer, unreachable!()
// we use the environment address to store the index relative to jumps // unsafe {
// so the address of the jump it's outside the wasm memory itself. // // Rather than using the env as the holder of the jump buffer pointer,
let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8; // // we use the environment address to store the index relative to jumps
// We create the jump buffer outside of the wasm memory // // so the address of the jump it's outside the wasm memory itself.
let jump_buf: UnsafeCell<[u32; 27]> = UnsafeCell::new([0; 27]); // let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
let jumps = &mut get_emscripten_data(ctx).jumps; // // We create the jump buffer outside of the wasm memory
let result = setjmp(jump_buf.get() as _); // let jump_buf: UnsafeCell<[u32; 27]> = UnsafeCell::new([0; 27]);
// We set the jump index to be the last 3value of jumps // let jumps = &mut get_emscripten_data(ctx).jumps;
*jump_index = jumps.len() as _; // let result = setjmp(jump_buf.get() as _);
// We hold the reference of the jump buffer // // We set the jump index to be the last 3value of jumps
jumps.push(jump_buf); // *jump_index = jumps.len() as _;
result // // We hold the reference of the jump buffer
} // jumps.push(jump_buf);
// result
// }
} }
/// longjmp /// longjmp
#[allow(unreachable_code)] #[allow(unreachable_code)]
pub fn __longjmp(ctx: &mut Ctx, env_addr: u32, val: c_int) { pub fn __longjmp(ctx: &mut Ctx, _env_addr: u32, _val: c_int) {
debug!("emscripten::__longjmp (longmp)"); debug!("emscripten::__longjmp (longmp)");
unsafe { abort_with_message(ctx, "missing function: _longjmp");
// We retrieve the jump index from the env address // unsafe {
let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8; // // We retrieve the jump index from the env address
let jumps = &mut get_emscripten_data(ctx).jumps; // let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
// We get the real jump buffer from the jumps vector, using the retrieved index // let jumps = &mut get_emscripten_data(ctx).jumps;
let jump_buf = &jumps[*jump_index as usize]; // // We get the real jump buffer from the jumps vector, using the retrieved index
longjmp(jump_buf.get() as _, val) // let jump_buf = &jumps[*jump_index as usize];
}; // longjmp(jump_buf.get() as _, val)
// };
} }
extern "C" { /// _longjmp
fn setjmp(env: *mut c_void) -> c_int; // This function differs from the js implementation, it should return Result<(), &'static str>
fn longjmp(env: *mut c_void, val: c_int) -> !; pub fn _longjmp(ctx: &mut Ctx, env_addr: i32, val: c_int) -> Result<(), ()> {
let val = if val == 0 { 1 } else { val };
get_emscripten_data(ctx)
.set_threw
.as_ref()
.expect("set_threw is None")
.call(env_addr, val)
.expect("set_threw failed to call");
// TODO: return Err("longjmp")
Err(())
} }
// extern "C" {
// fn setjmp(env: *mut c_void) -> c_int;
// fn longjmp(env: *mut c_void, val: c_int) -> !;
// }

View File

@ -27,17 +27,19 @@ mod file_descriptor;
pub mod stdio; pub mod stdio;
// EMSCRIPTEN APIS // EMSCRIPTEN APIS
mod bitwise;
mod emscripten_target; mod emscripten_target;
mod env; mod env;
mod errno; mod errno;
mod exception; mod exception;
mod exec;
mod exit;
mod io; mod io;
mod jmp; mod jmp;
mod linking; mod linking;
mod lock; mod lock;
mod math; mod math;
mod memory; mod memory;
mod nullfunc;
mod process; mod process;
mod signal; mod signal;
mod storage; mod storage;
@ -54,8 +56,6 @@ pub use self::utils::{
// TODO: Magic number - how is this calculated? // TODO: Magic number - how is this calculated?
const TOTAL_STACK: u32 = 5_242_880; const TOTAL_STACK: u32 = 5_242_880;
// TODO: Magic number - how is this calculated?
const DYNAMICTOP_PTR_DIFF: u32 = 1088;
// TODO: make this variable // TODO: make this variable
const STATIC_BUMP: u32 = 215_536; const STATIC_BUMP: u32 = 215_536;
@ -71,22 +71,6 @@ lazy_static! {
const GLOBAL_BASE: u32 = 1024; const GLOBAL_BASE: u32 = 1024;
const STATIC_BASE: u32 = GLOBAL_BASE; const STATIC_BASE: u32 = GLOBAL_BASE;
fn stacktop(static_bump: u32) -> u32 {
align_memory(dynamictop_ptr(static_bump) + 4)
}
fn stack_max(static_bump: u32) -> u32 {
stacktop(static_bump) + TOTAL_STACK
}
fn dynamic_base(static_bump: u32) -> u32 {
align_memory(stack_max(static_bump))
}
fn dynamictop_ptr(static_bump: u32) -> u32 {
static_bump + DYNAMICTOP_PTR_DIFF
}
pub struct EmscriptenData<'a> { pub struct EmscriptenData<'a> {
pub malloc: Func<'a, u32, u32>, pub malloc: Func<'a, u32, u32>,
pub free: Func<'a, u32>, pub free: Func<'a, u32>,
@ -99,6 +83,7 @@ pub struct EmscriptenData<'a> {
pub dyn_call_ii: Option<Func<'a, (i32, i32), i32>>, pub dyn_call_ii: Option<Func<'a, (i32, i32), i32>>,
pub dyn_call_iii: Option<Func<'a, (i32, i32, i32), i32>>, pub dyn_call_iii: Option<Func<'a, (i32, i32, i32), i32>>,
pub dyn_call_iiii: Option<Func<'a, (i32, i32, i32, i32), i32>>, pub dyn_call_iiii: Option<Func<'a, (i32, i32, i32, i32), i32>>,
pub dyn_call_iifi: Option<Func<'a, (i32, i32, f64, i32), i32>>,
pub dyn_call_v: Option<Func<'a, (i32)>>, pub dyn_call_v: Option<Func<'a, (i32)>>,
pub dyn_call_vi: Option<Func<'a, (i32, i32)>>, pub dyn_call_vi: Option<Func<'a, (i32, i32)>>,
pub dyn_call_vii: Option<Func<'a, (i32, i32, i32)>>, pub dyn_call_vii: Option<Func<'a, (i32, i32, i32)>>,
@ -110,15 +95,27 @@ pub struct EmscriptenData<'a> {
pub dyn_call_diiii: Option<Func<'a, (i32, i32, i32, i32, i32), f64>>, pub dyn_call_diiii: Option<Func<'a, (i32, i32, i32, i32, i32), f64>>,
pub dyn_call_iiiii: Option<Func<'a, (i32, i32, i32, i32, i32), i32>>, pub dyn_call_iiiii: Option<Func<'a, (i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32), i32>>, pub dyn_call_iiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiiiiii:
Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiiiiiii:
Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_vd: Option<Func<'a, (i32, f64)>>, pub dyn_call_vd: Option<Func<'a, (i32, f64)>>,
pub dyn_call_viiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiiiiiiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiiiiii:
Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_iij: Option<Func<'a, (i32, i32, i32, i32), i32>>,
pub dyn_call_iiji: Option<Func<'a, (i32, i32, i32, i32, i32), i32>>, pub dyn_call_iiji: Option<Func<'a, (i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_j: Option<Func<'a, i32, i32>>, pub dyn_call_j: Option<Func<'a, i32, i32>>,
pub dyn_call_ji: Option<Func<'a, (i32, i32), i32>>, pub dyn_call_ji: Option<Func<'a, (i32, i32), i32>>,
pub dyn_call_jii: Option<Func<'a, (i32, i32, i32), i32>>,
pub dyn_call_jij: Option<Func<'a, (i32, i32, i32, i32), i32>>, pub dyn_call_jij: Option<Func<'a, (i32, i32, i32, i32), i32>>,
pub dyn_call_jjj: Option<Func<'a, (i32, i32, i32, i32, i32), i32>>, pub dyn_call_jjj: Option<Func<'a, (i32, i32, i32, i32, i32), i32>>,
pub dyn_call_viiij: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiij: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
@ -129,10 +126,20 @@ pub struct EmscriptenData<'a> {
pub dyn_call_viiji: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viiji: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_viijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vj: Option<Func<'a, (i32, i32, i32)>>,
pub dyn_call_vij: Option<Func<'a, (i32, i32, i32, i32)>>, pub dyn_call_vij: Option<Func<'a, (i32, i32, i32, i32)>>,
pub dyn_call_viji: Option<Func<'a, (i32, i32, i32, i32, i32)>>, pub dyn_call_viji: Option<Func<'a, (i32, i32, i32, i32, i32)>>,
pub dyn_call_vijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>, pub dyn_call_vijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>, pub dyn_call_vijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viid: Option<Func<'a, (i32, i32, i32, f64)>>,
pub dyn_call_viidii: Option<Func<'a, (i32, i32, i32, f64, i32, i32)>>,
pub dyn_call_viidddddddd:
Option<Func<'a, (i32, i32, i32, f64, f64, f64, f64, f64, f64, f64, f64)>>,
pub temp_ret_0: i32,
pub stack_save: Option<Func<'a, (), i32>>,
pub stack_restore: Option<Func<'a, (i32)>>,
pub set_threw: Option<Func<'a, (i32, i32)>>,
} }
impl<'a> EmscriptenData<'a> { impl<'a> EmscriptenData<'a> {
@ -151,6 +158,7 @@ impl<'a> EmscriptenData<'a> {
let dyn_call_ii = instance.func("dynCall_ii").ok(); let dyn_call_ii = instance.func("dynCall_ii").ok();
let dyn_call_iii = instance.func("dynCall_iii").ok(); let dyn_call_iii = instance.func("dynCall_iii").ok();
let dyn_call_iiii = instance.func("dynCall_iiii").ok(); let dyn_call_iiii = instance.func("dynCall_iiii").ok();
let dyn_call_iifi = instance.func("dynCall_iifi").ok();
let dyn_call_v = instance.func("dynCall_v").ok(); let dyn_call_v = instance.func("dynCall_v").ok();
let dyn_call_vi = instance.func("dynCall_vi").ok(); let dyn_call_vi = instance.func("dynCall_vi").ok();
let dyn_call_vii = instance.func("dynCall_vii").ok(); let dyn_call_vii = instance.func("dynCall_vii").ok();
@ -162,15 +170,24 @@ impl<'a> EmscriptenData<'a> {
let dyn_call_diiii = instance.func("dynCall_diiii").ok(); let dyn_call_diiii = instance.func("dynCall_diiii").ok();
let dyn_call_iiiii = instance.func("dynCall_iiiii").ok(); let dyn_call_iiiii = instance.func("dynCall_iiiii").ok();
let dyn_call_iiiiii = instance.func("dynCall_iiiiii").ok(); let dyn_call_iiiiii = instance.func("dynCall_iiiiii").ok();
let dyn_call_iiiiiii = instance.func("dynCall_iiiiiii").ok();
let dyn_call_iiiiiiii = instance.func("dynCall_iiiiiiii").ok();
let dyn_call_iiiiiiiii = instance.func("dynCall_iiiiiiiii").ok();
let dyn_call_iiiiiiiiii = instance.func("dynCall_iiiiiiiiii").ok();
let dyn_call_iiiiiiiiiii = instance.func("dynCall_iiiiiiiiiii").ok();
let dyn_call_vd = instance.func("dynCall_vd").ok(); let dyn_call_vd = instance.func("dynCall_vd").ok();
let dyn_call_viiiii = instance.func("dynCall_viiiii").ok(); let dyn_call_viiiii = instance.func("dynCall_viiiii").ok();
let dyn_call_viiiiii = instance.func("dynCall_viiiiii").ok(); let dyn_call_viiiiii = instance.func("dynCall_viiiiii").ok();
let dyn_call_viiiiiii = instance.func("dynCall_viiiiiii").ok(); let dyn_call_viiiiiii = instance.func("dynCall_viiiiiii").ok();
let dyn_call_viiiiiiii = instance.func("dynCall_viiiiiiii").ok(); let dyn_call_viiiiiiii = instance.func("dynCall_viiiiiiii").ok();
let dyn_call_viiiiiiiii = instance.func("dynCall_viiiiiiiii").ok(); let dyn_call_viiiiiiiii = instance.func("dynCall_viiiiiiiii").ok();
let dyn_call_viiiiiiiiii = instance.func("dynCall_viiiiiiiiii").ok();
let dyn_call_iij = instance.func("dynCall_iij").ok();
let dyn_call_iiji = instance.func("dynCall_iiji").ok(); let dyn_call_iiji = instance.func("dynCall_iiji").ok();
let dyn_call_iiijj = instance.func("dynCall_iiijj").ok();
let dyn_call_j = instance.func("dynCall_j").ok(); let dyn_call_j = instance.func("dynCall_j").ok();
let dyn_call_ji = instance.func("dynCall_ji").ok(); let dyn_call_ji = instance.func("dynCall_ji").ok();
let dyn_call_jii = instance.func("dynCall_jii").ok();
let dyn_call_jij = instance.func("dynCall_jij").ok(); let dyn_call_jij = instance.func("dynCall_jij").ok();
let dyn_call_jjj = instance.func("dynCall_jjj").ok(); let dyn_call_jjj = instance.func("dynCall_jjj").ok();
let dyn_call_viiij = instance.func("dynCall_viiij").ok(); let dyn_call_viiij = instance.func("dynCall_viiij").ok();
@ -180,10 +197,18 @@ impl<'a> EmscriptenData<'a> {
let dyn_call_viiji = instance.func("dynCall_viiji").ok(); let dyn_call_viiji = instance.func("dynCall_viiji").ok();
let dyn_call_viijiii = instance.func("dynCall_viijiii").ok(); let dyn_call_viijiii = instance.func("dynCall_viijiii").ok();
let dyn_call_viijj = instance.func("dynCall_viijj").ok(); let dyn_call_viijj = instance.func("dynCall_viijj").ok();
let dyn_call_vj = instance.func("dynCall_vj").ok();
let dyn_call_vij = instance.func("dynCall_vij").ok(); let dyn_call_vij = instance.func("dynCall_vij").ok();
let dyn_call_viji = instance.func("dynCall_viji").ok(); let dyn_call_viji = instance.func("dynCall_viji").ok();
let dyn_call_vijiii = instance.func("dynCall_vijiii").ok(); let dyn_call_vijiii = instance.func("dynCall_vijiii").ok();
let dyn_call_vijj = instance.func("dynCall_vijj").ok(); let dyn_call_vijj = instance.func("dynCall_vijj").ok();
let dyn_call_viid = instance.func("dynCall_viid").ok();
let dyn_call_viidii = instance.func("dynCall_viidii").ok();
let dyn_call_viidddddddd = instance.func("dynCall_viidddddddd").ok();
let stack_save = instance.func("stackSave").ok();
let stack_restore = instance.func("stackRestore").ok();
let set_threw = instance.func("_setThrew").ok();
EmscriptenData { EmscriptenData {
malloc, malloc,
@ -196,6 +221,7 @@ impl<'a> EmscriptenData<'a> {
dyn_call_ii, dyn_call_ii,
dyn_call_iii, dyn_call_iii,
dyn_call_iiii, dyn_call_iiii,
dyn_call_iifi,
dyn_call_v, dyn_call_v,
dyn_call_vi, dyn_call_vi,
dyn_call_vii, dyn_call_vii,
@ -207,15 +233,24 @@ impl<'a> EmscriptenData<'a> {
dyn_call_diiii, dyn_call_diiii,
dyn_call_iiiii, dyn_call_iiiii,
dyn_call_iiiiii, dyn_call_iiiiii,
dyn_call_iiiiiii,
dyn_call_iiiiiiii,
dyn_call_iiiiiiiii,
dyn_call_iiiiiiiiii,
dyn_call_iiiiiiiiiii,
dyn_call_vd, dyn_call_vd,
dyn_call_viiiii, dyn_call_viiiii,
dyn_call_viiiiii, dyn_call_viiiiii,
dyn_call_viiiiiii, dyn_call_viiiiiii,
dyn_call_viiiiiiii, dyn_call_viiiiiiii,
dyn_call_viiiiiiiii, dyn_call_viiiiiiiii,
dyn_call_viiiiiiiiii,
dyn_call_iij,
dyn_call_iiji, dyn_call_iiji,
dyn_call_iiijj,
dyn_call_j, dyn_call_j,
dyn_call_ji, dyn_call_ji,
dyn_call_jii,
dyn_call_jij, dyn_call_jij,
dyn_call_jjj, dyn_call_jjj,
dyn_call_viiij, dyn_call_viiij,
@ -225,10 +260,19 @@ impl<'a> EmscriptenData<'a> {
dyn_call_viiji, dyn_call_viiji,
dyn_call_viijiii, dyn_call_viijiii,
dyn_call_viijj, dyn_call_viijj,
dyn_call_vj,
dyn_call_vij, dyn_call_vij,
dyn_call_viji, dyn_call_viji,
dyn_call_vijiii, dyn_call_vijiii,
dyn_call_vijj, dyn_call_vijj,
dyn_call_viid,
dyn_call_viidii,
dyn_call_viidddddddd,
temp_ret_0: 0,
stack_save,
stack_restore,
set_threw,
} }
} }
} }
@ -243,6 +287,12 @@ pub fn run_emscripten_instance(
let data_ptr = &mut data as *mut _ as *mut c_void; let data_ptr = &mut data as *mut _ as *mut c_void;
instance.context_mut().data = data_ptr; instance.context_mut().data = data_ptr;
// ATINIT
// (used by C++)
if let Ok(_func) = instance.dyn_func("globalCtors") {
instance.call("globalCtors", &[])?;
}
if let Ok(_func) = instance.dyn_func("___emscripten_environ_constructor") { if let Ok(_func) = instance.dyn_func("___emscripten_environ_constructor") {
instance.call("___emscripten_environ_constructor", &[])?; instance.call("___emscripten_environ_constructor", &[])?;
} }
@ -265,7 +315,7 @@ pub fn run_emscripten_instance(
), ),
}; };
// TODO atinit and atexit for emscripten // TODO atexit for emscripten
// println!("{:?}", data); // println!("{:?}", data);
Ok(()) Ok(())
} }
@ -309,10 +359,6 @@ pub struct EmscriptenGlobalsData {
table_base: u32, table_base: u32,
temp_double_ptr: u32, temp_double_ptr: u32,
use_old_abort_on_cannot_grow_memory: bool, use_old_abort_on_cannot_grow_memory: bool,
// Global namespace
infinity: f64,
nan: f64,
} }
pub struct EmscriptenGlobals { pub struct EmscriptenGlobals {
@ -323,6 +369,7 @@ pub struct EmscriptenGlobals {
pub table: Table, pub table: Table,
pub memory_min: Pages, pub memory_min: Pages,
pub memory_max: Option<Pages>, pub memory_max: Option<Pages>,
pub null_func_names: Vec<String>,
} }
impl EmscriptenGlobals { impl EmscriptenGlobals {
@ -341,7 +388,7 @@ impl EmscriptenGlobals {
if name == "abortOnCannotGrowMemory" && namespace == "env" { if name == "abortOnCannotGrowMemory" && namespace == "env" {
let sig_index = module.info().func_assoc[index.convert_up(module.info())]; let sig_index = module.info().func_assoc[index.convert_up(module.info())];
let expected_sig = &module.info().signatures[sig_index]; let expected_sig = &module.info().signatures[sig_index];
if **expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG { if *expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG {
use_old_abort_on_cannot_grow_memory = true; use_old_abort_on_cannot_grow_memory = true;
} }
break; break;
@ -364,22 +411,22 @@ impl EmscriptenGlobals {
minimum: table_min, minimum: table_min,
maximum: table_max, maximum: table_max,
}; };
let mut table = Table::new(table_type).unwrap(); let table = Table::new(table_type).unwrap();
let data = { let data = {
let static_bump = STATIC_BUMP; let static_bump = STATIC_BUMP;
let mut STATIC_TOP = STATIC_BASE + static_bump; let mut static_top = STATIC_BASE + static_bump;
let memory_base = STATIC_BASE; let memory_base = STATIC_BASE;
let table_base = 0; let table_base = 0;
let temp_double_ptr = STATIC_TOP; let temp_double_ptr = static_top;
STATIC_TOP += 16; static_top += 16;
let dynamictop_ptr = static_alloc(&mut STATIC_TOP, 4); let dynamictop_ptr = static_alloc(&mut static_top, 4);
let stacktop = align_memory(STATIC_TOP); let stacktop = align_memory(static_top);
let stack_max = stacktop + TOTAL_STACK; let stack_max = stacktop + TOTAL_STACK;
EmscriptenGlobalsData { EmscriptenGlobalsData {
@ -391,20 +438,34 @@ impl EmscriptenGlobals {
table_base, table_base,
temp_double_ptr, temp_double_ptr,
use_old_abort_on_cannot_grow_memory, use_old_abort_on_cannot_grow_memory,
infinity: std::f64::INFINITY,
nan: std::f64::NAN,
} }
}; };
emscripten_set_up_memory(&memory, &data); emscripten_set_up_memory(&memory, &data);
let mut null_func_names = vec![];
for (
_,
ImportName {
namespace_index,
name_index,
},
) in &module.info().imported_functions
{
let namespace = module.info().namespace_table.get(*namespace_index);
let name = module.info().name_table.get(*name_index);
if namespace == "env" && name.starts_with("nullFunc_") {
null_func_names.push(name.to_string())
}
}
Self { Self {
data, data,
memory, memory,
table, table,
memory_min, memory_min,
memory_max, memory_max,
null_func_names,
} }
} }
} }
@ -416,291 +477,349 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
func!(crate::memory::abort_on_cannot_grow_memory).to_export() func!(crate::memory::abort_on_cannot_grow_memory).to_export()
}; };
imports! { let mut env_ns = namespace! {
"env" => { "memory" => Export::Memory(globals.memory.clone()),
"memory" => Export::Memory(globals.memory.clone()), "table" => Export::Table(globals.table.clone()),
"table" => Export::Table(globals.table.clone()),
// Globals // Globals
"STACKTOP" => Global::new(Value::I32(globals.data.stacktop as i32)), "STACKTOP" => Global::new(Value::I32(globals.data.stacktop as i32)),
"STACK_MAX" => Global::new(Value::I32(globals.data.stack_max as i32)), "STACK_MAX" => Global::new(Value::I32(globals.data.stack_max as i32)),
"DYNAMICTOP_PTR" => Global::new(Value::I32(globals.data.dynamictop_ptr as i32)), "DYNAMICTOP_PTR" => Global::new(Value::I32(globals.data.dynamictop_ptr as i32)),
"tableBase" => Global::new(Value::I32(globals.data.table_base as i32)), "tableBase" => Global::new(Value::I32(globals.data.table_base as i32)),
"__table_base" => Global::new(Value::I32(globals.data.table_base as i32)), "__table_base" => Global::new(Value::I32(globals.data.table_base as i32)),
"ABORT" => Global::new(Value::I32(globals.data.abort as i32)), "ABORT" => Global::new(Value::I32(globals.data.abort as i32)),
"memoryBase" => Global::new(Value::I32(globals.data.memory_base as i32)), "memoryBase" => Global::new(Value::I32(globals.data.memory_base as i32)),
"__memory_base" => Global::new(Value::I32(globals.data.memory_base as i32)), "__memory_base" => Global::new(Value::I32(globals.data.memory_base as i32)),
"tempDoublePtr" => Global::new(Value::I32(globals.data.temp_double_ptr as i32)), "tempDoublePtr" => Global::new(Value::I32(globals.data.temp_double_ptr as i32)),
// IO // IO
"printf" => func!(crate::io::printf), "printf" => func!(crate::io::printf),
"putchar" => func!(crate::io::putchar), "putchar" => func!(crate::io::putchar),
"___lock" => func!(crate::lock::___lock), "___lock" => func!(crate::lock::___lock),
"___unlock" => func!(crate::lock::___unlock), "___unlock" => func!(crate::lock::___unlock),
"___wait" => func!(crate::lock::___wait), "___wait" => func!(crate::lock::___wait),
"_flock" => func!(crate::lock::_flock),
"_chroot" => func!(crate::io::chroot),
"_getprotobyname" => func!(crate::io::getprotobyname),
"_getprotobynumber" => func!(crate::io::getprotobynumber),
"_getpwuid" => func!(crate::io::getpwuid),
"_sigdelset" => func!(crate::io::sigdelset),
"_sigfillset" => func!(crate::io::sigfillset),
"_tzset" => func!(crate::io::tzset),
"_strptime" => func!(crate::io::strptime),
// Env // exec
"___assert_fail" => func!(crate::env::___assert_fail), "_execvp" => func!(crate::exec::execvp),
"_getenv" => func!(crate::env::_getenv), "_execl" => func!(crate::exec::execl),
"_setenv" => func!(crate::env::_setenv), "_execle" => func!(crate::exec::execle),
"_putenv" => func!(crate::env::_putenv),
"_unsetenv" => func!(crate::env::_unsetenv),
"_getpwnam" => func!(crate::env::_getpwnam),
"_getgrnam" => func!(crate::env::_getgrnam),
"___buildEnvironment" => func!(crate::env::___build_environment),
"___setErrNo" => func!(crate::errno::___seterrno),
"_getpagesize" => func!(crate::env::_getpagesize),
"_sysconf" => func!(crate::env::_sysconf),
"_getaddrinfo" => func!(crate::env::_getaddrinfo),
// Null func // exit
"nullFunc_i" => func!(crate::nullfunc::nullfunc_i), "__exit" => func!(crate::exit::exit),
"nullFunc_ii" => func!(crate::nullfunc::nullfunc_ii),
"nullFunc_iii" => func!(crate::nullfunc::nullfunc_iii),
"nullFunc_iiii" => func!(crate::nullfunc::nullfunc_iiii),
"nullFunc_iiiii" => func!(crate::nullfunc::nullfunc_iiiii),
"nullFunc_iiiiii" => func!(crate::nullfunc::nullfunc_iiiiii),
"nullFunc_v" => func!(crate::nullfunc::nullfunc_v),
"nullFunc_vi" => func!(crate::nullfunc::nullfunc_vi),
"nullFunc_vii" => func!(crate::nullfunc::nullfunc_vii),
"nullFunc_viii" => func!(crate::nullfunc::nullfunc_viii),
"nullFunc_viiii" => func!(crate::nullfunc::nullfunc_viiii),
"nullFunc_viiiii" => func!(crate::nullfunc::nullfunc_viiiii),
"nullFunc_viiiiii" => func!(crate::nullfunc::nullfunc_viiiiii),
// Syscalls // Env
"___syscall1" => func!(crate::syscalls::___syscall1), "___assert_fail" => func!(crate::env::___assert_fail),
"___syscall3" => func!(crate::syscalls::___syscall3), "_getenv" => func!(crate::env::_getenv),
"___syscall4" => func!(crate::syscalls::___syscall4), "_setenv" => func!(crate::env::_setenv),
"___syscall5" => func!(crate::syscalls::___syscall5), "_putenv" => func!(crate::env::_putenv),
"___syscall6" => func!(crate::syscalls::___syscall6), "_unsetenv" => func!(crate::env::_unsetenv),
"___syscall10" => func!(crate::syscalls::___syscall10), "_getpwnam" => func!(crate::env::_getpwnam),
"___syscall12" => func!(crate::syscalls::___syscall12), "_getgrnam" => func!(crate::env::_getgrnam),
"___syscall15" => func!(crate::syscalls::___syscall15), "___buildEnvironment" => func!(crate::env::___build_environment),
"___syscall20" => func!(crate::syscalls::___syscall20), "___setErrNo" => func!(crate::errno::___seterrno),
"___syscall39" => func!(crate::syscalls::___syscall39), "_getpagesize" => func!(crate::env::_getpagesize),
"___syscall38" => func!(crate::syscalls::___syscall38), "_sysconf" => func!(crate::env::_sysconf),
"___syscall40" => func!(crate::syscalls::___syscall40), "_getaddrinfo" => func!(crate::env::_getaddrinfo),
"___syscall54" => func!(crate::syscalls::___syscall54), "_times" => func!(crate::env::_times),
"___syscall57" => func!(crate::syscalls::___syscall57),
"___syscall60" => func!(crate::syscalls::___syscall60),
"___syscall63" => func!(crate::syscalls::___syscall63),
"___syscall64" => func!(crate::syscalls::___syscall64),
"___syscall66" => func!(crate::syscalls::___syscall66),
"___syscall75" => func!(crate::syscalls::___syscall75),
"___syscall85" => func!(crate::syscalls::___syscall85),
"___syscall91" => func!(crate::syscalls::___syscall191),
"___syscall97" => func!(crate::syscalls::___syscall97),
"___syscall102" => func!(crate::syscalls::___syscall102),
"___syscall110" => func!(crate::syscalls::___syscall110),
"___syscall114" => func!(crate::syscalls::___syscall114),
"___syscall122" => func!(crate::syscalls::___syscall122),
"___syscall140" => func!(crate::syscalls::___syscall140),
"___syscall142" => func!(crate::syscalls::___syscall142),
"___syscall145" => func!(crate::syscalls::___syscall145),
"___syscall146" => func!(crate::syscalls::___syscall146),
"___syscall168" => func!(crate::syscalls::___syscall168),
"___syscall180" => func!(crate::syscalls::___syscall180),
"___syscall181" => func!(crate::syscalls::___syscall181),
"___syscall191" => func!(crate::syscalls::___syscall191),
"___syscall192" => func!(crate::syscalls::___syscall192),
"___syscall194" => func!(crate::syscalls::___syscall194),
"___syscall195" => func!(crate::syscalls::___syscall195),
"___syscall196" => func!(crate::syscalls::___syscall196),
"___syscall197" => func!(crate::syscalls::___syscall197),
"___syscall199" => func!(crate::syscalls::___syscall199),
"___syscall201" => func!(crate::syscalls::___syscall201),
"___syscall202" => func!(crate::syscalls::___syscall202),
"___syscall212" => func!(crate::syscalls::___syscall212),
"___syscall220" => func!(crate::syscalls::___syscall220),
"___syscall221" => func!(crate::syscalls::___syscall221),
"___syscall268" => func!(crate::syscalls::___syscall268),
"___syscall272" => func!(crate::syscalls::___syscall272),
"___syscall295" => func!(crate::syscalls::___syscall295),
"___syscall300" => func!(crate::syscalls::___syscall300),
"___syscall330" => func!(crate::syscalls::___syscall330),
"___syscall334" => func!(crate::syscalls::___syscall334),
"___syscall340" => func!(crate::syscalls::___syscall340),
// Process // Syscalls
"abort" => func!(crate::process::em_abort), "___syscall1" => func!(crate::syscalls::___syscall1),
"_abort" => func!(crate::process::_abort), "___syscall3" => func!(crate::syscalls::___syscall3),
"abortStackOverflow" => func!(crate::process::abort_stack_overflow), "___syscall4" => func!(crate::syscalls::___syscall4),
"_llvm_trap" => func!(crate::process::_llvm_trap), "___syscall5" => func!(crate::syscalls::___syscall5),
"_fork" => func!(crate::process::_fork), "___syscall6" => func!(crate::syscalls::___syscall6),
"_exit" => func!(crate::process::_exit), "___syscall9" => func!(crate::syscalls::___syscall9),
"_system" => func!(crate::process::_system), "___syscall10" => func!(crate::syscalls::___syscall10),
"_popen" => func!(crate::process::_popen), "___syscall12" => func!(crate::syscalls::___syscall12),
"_endgrent" => func!(crate::process::_endgrent), "___syscall15" => func!(crate::syscalls::___syscall15),
"_execve" => func!(crate::process::_execve), "___syscall20" => func!(crate::syscalls::___syscall20),
"_kill" => func!(crate::process::_kill), "___syscall33" => func!(crate::syscalls::___syscall33),
"_llvm_stackrestore" => func!(crate::process::_llvm_stackrestore), "___syscall34" => func!(crate::syscalls::___syscall34),
"_llvm_stacksave" => func!(crate::process::_llvm_stacksave), "___syscall39" => func!(crate::syscalls::___syscall39),
"_raise" => func!(crate::process::_raise), "___syscall38" => func!(crate::syscalls::___syscall38),
"_sem_init" => func!(crate::process::_sem_init), "___syscall40" => func!(crate::syscalls::___syscall40),
"_sem_post" => func!(crate::process::_sem_post), "___syscall41" => func!(crate::syscalls::___syscall41),
"_sem_wait" => func!(crate::process::_sem_wait), "___syscall42" => func!(crate::syscalls::___syscall42),
"_getgrent" => func!(crate::process::_getgrent), "___syscall54" => func!(crate::syscalls::___syscall54),
"_sched_yield" => func!(crate::process::_sched_yield), "___syscall57" => func!(crate::syscalls::___syscall57),
"_setgrent" => func!(crate::process::_setgrent), "___syscall60" => func!(crate::syscalls::___syscall60),
"_setgroups" => func!(crate::process::_setgroups), "___syscall63" => func!(crate::syscalls::___syscall63),
"_setitimer" => func!(crate::process::_setitimer), "___syscall64" => func!(crate::syscalls::___syscall64),
"_usleep" => func!(crate::process::_usleep), "___syscall66" => func!(crate::syscalls::___syscall66),
"_utimes" => func!(crate::process::_utimes), "___syscall75" => func!(crate::syscalls::___syscall75),
"_waitpid" => func!(crate::process::_waitpid), "___syscall77" => func!(crate::syscalls::___syscall77),
"___syscall83" => func!(crate::syscalls::___syscall83),
"___syscall85" => func!(crate::syscalls::___syscall85),
"___syscall91" => func!(crate::syscalls::___syscall91),
"___syscall94" => func!(crate::syscalls::___syscall94),
"___syscall97" => func!(crate::syscalls::___syscall97),
"___syscall102" => func!(crate::syscalls::___syscall102),
"___syscall110" => func!(crate::syscalls::___syscall110),
"___syscall114" => func!(crate::syscalls::___syscall114),
"___syscall118" => func!(crate::syscalls::___syscall118),
"___syscall122" => func!(crate::syscalls::___syscall122),
"___syscall140" => func!(crate::syscalls::___syscall140),
"___syscall142" => func!(crate::syscalls::___syscall142),
"___syscall145" => func!(crate::syscalls::___syscall145),
"___syscall146" => func!(crate::syscalls::___syscall146),
"___syscall148" => func!(crate::syscalls::___syscall148),
"___syscall168" => func!(crate::syscalls::___syscall168),
"___syscall180" => func!(crate::syscalls::___syscall180),
"___syscall181" => func!(crate::syscalls::___syscall181),
"___syscall183" => func!(crate::syscalls::___syscall183),
"___syscall191" => func!(crate::syscalls::___syscall191),
"___syscall192" => func!(crate::syscalls::___syscall192),
"___syscall194" => func!(crate::syscalls::___syscall194),
"___syscall195" => func!(crate::syscalls::___syscall195),
"___syscall196" => func!(crate::syscalls::___syscall196),
"___syscall197" => func!(crate::syscalls::___syscall197),
"___syscall198" => func!(crate::syscalls::___syscall198),
"___syscall199" => func!(crate::syscalls::___syscall199),
"___syscall200" => func!(crate::syscalls::___syscall200),
"___syscall201" => func!(crate::syscalls::___syscall201),
"___syscall202" => func!(crate::syscalls::___syscall202),
"___syscall205" => func!(crate::syscalls::___syscall205),
"___syscall207" => func!(crate::syscalls::___syscall207),
"___syscall212" => func!(crate::syscalls::___syscall212),
"___syscall219" => func!(crate::syscalls::___syscall219),
"___syscall220" => func!(crate::syscalls::___syscall220),
"___syscall221" => func!(crate::syscalls::___syscall221),
"___syscall268" => func!(crate::syscalls::___syscall268),
"___syscall272" => func!(crate::syscalls::___syscall272),
"___syscall295" => func!(crate::syscalls::___syscall295),
"___syscall300" => func!(crate::syscalls::___syscall300),
"___syscall324" => func!(crate::syscalls::___syscall324),
"___syscall330" => func!(crate::syscalls::___syscall330),
"___syscall334" => func!(crate::syscalls::___syscall334),
"___syscall340" => func!(crate::syscalls::___syscall340),
// Process
"abort" => func!(crate::process::em_abort),
"_abort" => func!(crate::process::_abort),
"abortStackOverflow" => func!(crate::process::abort_stack_overflow),
"_llvm_trap" => func!(crate::process::_llvm_trap),
"_fork" => func!(crate::process::_fork),
"_exit" => func!(crate::process::_exit),
"_system" => func!(crate::process::_system),
"_popen" => func!(crate::process::_popen),
"_endgrent" => func!(crate::process::_endgrent),
"_execve" => func!(crate::process::_execve),
"_kill" => func!(crate::process::_kill),
"_llvm_stackrestore" => func!(crate::process::_llvm_stackrestore),
"_llvm_stacksave" => func!(crate::process::_llvm_stacksave),
"_llvm_eh_typeid_for" => func!(crate::process::_llvm_eh_typeid_for),
"_raise" => func!(crate::process::_raise),
"_sem_init" => func!(crate::process::_sem_init),
"_sem_post" => func!(crate::process::_sem_post),
"_sem_wait" => func!(crate::process::_sem_wait),
"_getgrent" => func!(crate::process::_getgrent),
"_sched_yield" => func!(crate::process::_sched_yield),
"_setgrent" => func!(crate::process::_setgrent),
"_setgroups" => func!(crate::process::_setgroups),
"_setitimer" => func!(crate::process::_setitimer),
"_usleep" => func!(crate::process::_usleep),
"_nanosleep" => func!(crate::process::_nanosleep),
"_utimes" => func!(crate::process::_utimes),
"_waitpid" => func!(crate::process::_waitpid),
// Signal // Signal
"_sigemptyset" => func!(crate::signal::_sigemptyset), "_sigemptyset" => func!(crate::signal::_sigemptyset),
"_sigaddset" => func!(crate::signal::_sigaddset), "_sigaddset" => func!(crate::signal::_sigaddset),
"_sigprocmask" => func!(crate::signal::_sigprocmask), "_sigprocmask" => func!(crate::signal::_sigprocmask),
"_sigaction" => func!(crate::signal::_sigaction), "_sigaction" => func!(crate::signal::_sigaction),
"_signal" => func!(crate::signal::_signal), "_signal" => func!(crate::signal::_signal),
"_sigsuspend" => func!(crate::signal::_sigsuspend), "_sigsuspend" => func!(crate::signal::_sigsuspend),
// Memory // Memory
"abortOnCannotGrowMemory" => abort_on_cannot_grow_memory_export, "abortOnCannotGrowMemory" => abort_on_cannot_grow_memory_export,
"_emscripten_memcpy_big" => func!(crate::memory::_emscripten_memcpy_big), "_emscripten_memcpy_big" => func!(crate::memory::_emscripten_memcpy_big),
"_emscripten_get_heap_size" => func!(crate::memory::_emscripten_get_heap_size), "_emscripten_get_heap_size" => func!(crate::memory::_emscripten_get_heap_size),
"_emscripten_resize_heap" => func!(crate::memory::_emscripten_resize_heap), "_emscripten_resize_heap" => func!(crate::memory::_emscripten_resize_heap),
"enlargeMemory" => func!(crate::memory::enlarge_memory), "enlargeMemory" => func!(crate::memory::enlarge_memory),
"getTotalMemory" => func!(crate::memory::get_total_memory), "getTotalMemory" => func!(crate::memory::get_total_memory),
"___map_file" => func!(crate::memory::___map_file), "___map_file" => func!(crate::memory::___map_file),
// Exception // Exception
"___cxa_allocate_exception" => func!(crate::exception::___cxa_allocate_exception), "___cxa_allocate_exception" => func!(crate::exception::___cxa_allocate_exception),
"___cxa_throw" => func!(crate::exception::___cxa_throw), "___cxa_throw" => func!(crate::exception::___cxa_throw),
"___cxa_begin_catch" => func!(crate::exception::___cxa_begin_catch),
"___cxa_end_catch" => func!(crate::exception::___cxa_end_catch),
"___cxa_uncaught_exception" => func!(crate::exception::___cxa_uncaught_exception),
// Time // Time
"_gettimeofday" => func!(crate::time::_gettimeofday), "_gettimeofday" => func!(crate::time::_gettimeofday),
"_clock_gettime" => func!(crate::time::_clock_gettime), "_clock_gettime" => func!(crate::time::_clock_gettime),
"___clock_gettime" => func!(crate::time::_clock_gettime), "___clock_gettime" => func!(crate::time::_clock_gettime),
"_clock" => func!(crate::time::_clock), "_clock" => func!(crate::time::_clock),
"_difftime" => func!(crate::time::_difftime), "_difftime" => func!(crate::time::_difftime),
"_asctime" => func!(crate::time::_asctime), "_asctime" => func!(crate::time::_asctime),
"_asctime_r" => func!(crate::time::_asctime_r), "_asctime_r" => func!(crate::time::_asctime_r),
"_localtime" => func!(crate::time::_localtime), "_localtime" => func!(crate::time::_localtime),
"_time" => func!(crate::time::_time), "_time" => func!(crate::time::_time),
"_strftime" => func!(crate::time::_strftime), "_strftime" => func!(crate::time::_strftime),
"_localtime_r" => func!(crate::time::_localtime_r), "_strftime_l" => func!(crate::time::_strftime_l),
"_gmtime_r" => func!(crate::time::_gmtime_r), "_localtime_r" => func!(crate::time::_localtime_r),
"_mktime" => func!(crate::time::_mktime), "_gmtime_r" => func!(crate::time::_gmtime_r),
"_gmtime" => func!(crate::time::_gmtime), "_mktime" => func!(crate::time::_mktime),
"_gmtime" => func!(crate::time::_gmtime),
// Math // Math
"f64-rem" => func!(crate::math::f64_rem), "f64-rem" => func!(crate::math::f64_rem),
"_llvm_log10_f64" => func!(crate::math::_llvm_log10_f64), "_llvm_log10_f64" => func!(crate::math::_llvm_log10_f64),
"_llvm_log2_f64" => func!(crate::math::_llvm_log2_f64), "_llvm_log2_f64" => func!(crate::math::_llvm_log2_f64),
"_llvm_log10_f32" => func!(crate::math::_llvm_log10_f32), "_llvm_log10_f32" => func!(crate::math::_llvm_log10_f32),
"_llvm_log2_f32" => func!(crate::math::_llvm_log2_f64), "_llvm_log2_f32" => func!(crate::math::_llvm_log2_f64),
"_emscripten_random" => func!(crate::math::_emscripten_random), "_llvm_sin_f64" => func!(crate::math::_llvm_sin_f64),
"_llvm_cos_f64" => func!(crate::math::_llvm_cos_f64),
"_llvm_exp2_f32" => func!(crate::math::_llvm_exp2_f32),
"_llvm_exp2_f64" => func!(crate::math::_llvm_exp2_f64),
"_emscripten_random" => func!(crate::math::_emscripten_random),
// Jump // Jump
"__setjmp" => func!(crate::jmp::__setjmp), "__setjmp" => func!(crate::jmp::__setjmp),
"__longjmp" => func!(crate::jmp::__longjmp), "__longjmp" => func!(crate::jmp::__longjmp),
"_longjmp" => func!(crate::jmp::_longjmp),
"_emscripten_longjmp" => func!(crate::jmp::_longjmp),
// Linking // Bitwise
"_dlclose" => func!(crate::linking::_dlclose), "_llvm_bswap_i64" => func!(crate::bitwise::_llvm_bswap_i64),
"_dlerror" => func!(crate::linking::_dlerror),
"_dlopen" => func!(crate::linking::_dlopen),
"_dlsym" => func!(crate::linking::_dlsym),
// wasm32-unknown-emscripten // Linking
"setTempRet0" => func!(crate::emscripten_target::setTempRet0), "_dlclose" => func!(crate::linking::_dlclose),
"getTempRet0" => func!(crate::emscripten_target::getTempRet0), "_dlerror" => func!(crate::linking::_dlerror),
"nullFunc_ji" => func!(crate::emscripten_target::nullFunc_ji), "_dlopen" => func!(crate::linking::_dlopen),
"invoke_i" => func!(crate::emscripten_target::invoke_i), "_dlsym" => func!(crate::linking::_dlsym),
"invoke_ii" => func!(crate::emscripten_target::invoke_ii),
"invoke_iii" => func!(crate::emscripten_target::invoke_iii), // wasm32-unknown-emscripten
"invoke_iiii" => func!(crate::emscripten_target::invoke_iiii), "setTempRet0" => func!(crate::emscripten_target::setTempRet0),
"invoke_v" => func!(crate::emscripten_target::invoke_v), "getTempRet0" => func!(crate::emscripten_target::getTempRet0),
"invoke_vi" => func!(crate::emscripten_target::invoke_vi), "invoke_i" => func!(crate::emscripten_target::invoke_i),
"invoke_vii" => func!(crate::emscripten_target::invoke_vii), "invoke_ii" => func!(crate::emscripten_target::invoke_ii),
"invoke_viii" => func!(crate::emscripten_target::invoke_viii), "invoke_iii" => func!(crate::emscripten_target::invoke_iii),
"invoke_viiii" => func!(crate::emscripten_target::invoke_viiii), "invoke_iiii" => func!(crate::emscripten_target::invoke_iiii),
"__Unwind_Backtrace" => func!(crate::emscripten_target::__Unwind_Backtrace), "invoke_iifi" => func!(crate::emscripten_target::invoke_iifi),
"__Unwind_FindEnclosingFunction" => func!(crate::emscripten_target::__Unwind_FindEnclosingFunction), "invoke_v" => func!(crate::emscripten_target::invoke_v),
"__Unwind_GetIPInfo" => func!(crate::emscripten_target::__Unwind_GetIPInfo), "invoke_vi" => func!(crate::emscripten_target::invoke_vi),
"___cxa_find_matching_catch_2" => func!(crate::emscripten_target::___cxa_find_matching_catch_2), "invoke_vj" => func!(crate::emscripten_target::invoke_vj),
"___cxa_find_matching_catch_3" => func!(crate::emscripten_target::___cxa_find_matching_catch_3), "invoke_vii" => func!(crate::emscripten_target::invoke_vii),
"___cxa_free_exception" => func!(crate::emscripten_target::___cxa_free_exception), "invoke_viii" => func!(crate::emscripten_target::invoke_viii),
"___resumeException" => func!(crate::emscripten_target::___resumeException), "invoke_viiii" => func!(crate::emscripten_target::invoke_viiii),
"_dladdr" => func!(crate::emscripten_target::_dladdr), "__Unwind_Backtrace" => func!(crate::emscripten_target::__Unwind_Backtrace),
"_pthread_cond_destroy" => func!(crate::emscripten_target::_pthread_cond_destroy), "__Unwind_FindEnclosingFunction" => func!(crate::emscripten_target::__Unwind_FindEnclosingFunction),
"_pthread_cond_init" => func!(crate::emscripten_target::_pthread_cond_init), "__Unwind_GetIPInfo" => func!(crate::emscripten_target::__Unwind_GetIPInfo),
"_pthread_cond_signal" => func!(crate::emscripten_target::_pthread_cond_signal), "___cxa_find_matching_catch_2" => func!(crate::emscripten_target::___cxa_find_matching_catch_2),
"_pthread_cond_wait" => func!(crate::emscripten_target::_pthread_cond_wait), "___cxa_find_matching_catch_3" => func!(crate::emscripten_target::___cxa_find_matching_catch_3),
"_pthread_condattr_destroy" => func!(crate::emscripten_target::_pthread_condattr_destroy), "___cxa_free_exception" => func!(crate::emscripten_target::___cxa_free_exception),
"_pthread_condattr_init" => func!(crate::emscripten_target::_pthread_condattr_init), "___resumeException" => func!(crate::emscripten_target::___resumeException),
"_pthread_condattr_setclock" => func!(crate::emscripten_target::_pthread_condattr_setclock), "_dladdr" => func!(crate::emscripten_target::_dladdr),
"_pthread_mutex_destroy" => func!(crate::emscripten_target::_pthread_mutex_destroy), "_pthread_create" => func!(crate::emscripten_target::_pthread_create),
"_pthread_mutex_init" => func!(crate::emscripten_target::_pthread_mutex_init), "_pthread_join" => func!(crate::emscripten_target::_pthread_join),
"_pthread_mutexattr_destroy" => func!(crate::emscripten_target::_pthread_mutexattr_destroy), "_pthread_cond_destroy" => func!(crate::emscripten_target::_pthread_cond_destroy),
"_pthread_mutexattr_init" => func!(crate::emscripten_target::_pthread_mutexattr_init), "_pthread_cond_init" => func!(crate::emscripten_target::_pthread_cond_init),
"_pthread_mutexattr_settype" => func!(crate::emscripten_target::_pthread_mutexattr_settype), "_pthread_cond_signal" => func!(crate::emscripten_target::_pthread_cond_signal),
"_pthread_rwlock_rdlock" => func!(crate::emscripten_target::_pthread_rwlock_rdlock), "_pthread_cond_wait" => func!(crate::emscripten_target::_pthread_cond_wait),
"_pthread_rwlock_unlock" => func!(crate::emscripten_target::_pthread_rwlock_unlock), "_pthread_condattr_destroy" => func!(crate::emscripten_target::_pthread_condattr_destroy),
"___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0), "_pthread_condattr_init" => func!(crate::emscripten_target::_pthread_condattr_init),
// round 2 "_pthread_condattr_setclock" => func!(crate::emscripten_target::_pthread_condattr_setclock),
"nullFunc_dii" => func!(crate::emscripten_target::nullFunc_dii), "_pthread_mutex_destroy" => func!(crate::emscripten_target::_pthread_mutex_destroy),
"nullFunc_diiii" => func!(crate::emscripten_target::nullFunc_diiii), "_pthread_mutex_init" => func!(crate::emscripten_target::_pthread_mutex_init),
"nullFunc_iiji" => func!(crate::emscripten_target::nullFunc_iiji), "_pthread_mutexattr_destroy" => func!(crate::emscripten_target::_pthread_mutexattr_destroy),
"nullFunc_j" => func!(crate::emscripten_target::nullFunc_j), "_pthread_mutexattr_init" => func!(crate::emscripten_target::_pthread_mutexattr_init),
"nullFunc_jij" => func!(crate::emscripten_target::nullFunc_jij), "_pthread_mutexattr_settype" => func!(crate::emscripten_target::_pthread_mutexattr_settype),
"nullFunc_jjj" => func!(crate::emscripten_target::nullFunc_jjj), "_pthread_rwlock_rdlock" => func!(crate::emscripten_target::_pthread_rwlock_rdlock),
"nullFunc_vd" => func!(crate::emscripten_target::nullFunc_vd), "_pthread_rwlock_unlock" => func!(crate::emscripten_target::_pthread_rwlock_unlock),
"nullFunc_viiiiiii" => func!(crate::emscripten_target::nullFunc_viiiiiii), "_pthread_setcancelstate" => func!(crate::emscripten_target::_pthread_setcancelstate),
"nullFunc_viiiiiiii" => func!(crate::emscripten_target::nullFunc_viiiiiiii), "_pthread_getspecific" => func!(crate::emscripten_target::_pthread_getspecific),
"nullFunc_viiiiiiiii" => func!(crate::emscripten_target::nullFunc_viiiiiiiii), "_pthread_setspecific" => func!(crate::emscripten_target::_pthread_setspecific),
"nullFunc_viiij" => func!(crate::emscripten_target::nullFunc_viiij), "_pthread_once" => func!(crate::emscripten_target::_pthread_once),
"nullFunc_viiijiiii" => func!(crate::emscripten_target::nullFunc_viiijiiii), "_pthread_key_create" => func!(crate::emscripten_target::_pthread_key_create),
"nullFunc_viiijiiiiii" => func!(crate::emscripten_target::nullFunc_viiijiiiiii), "___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0),
"nullFunc_viij" => func!(crate::emscripten_target::nullFunc_viij), "_getdtablesize" => func!(crate::emscripten_target::_getdtablesize),
"nullFunc_viiji" => func!(crate::emscripten_target::nullFunc_viiji), "_gethostbyaddr" => func!(crate::emscripten_target::_gethostbyaddr),
"nullFunc_viijiii" => func!(crate::emscripten_target::nullFunc_viijiii), "_gethostbyname_r" => func!(crate::emscripten_target::_gethostbyname_r),
"nullFunc_viijj" => func!(crate::emscripten_target::nullFunc_viijj), "_getloadavg" => func!(crate::emscripten_target::_getloadavg),
"nullFunc_vij" => func!(crate::emscripten_target::nullFunc_vij), "invoke_dii" => func!(crate::emscripten_target::invoke_dii),
"nullFunc_viji" => func!(crate::emscripten_target::nullFunc_viji), "invoke_diiii" => func!(crate::emscripten_target::invoke_diiii),
"nullFunc_vijiii" => func!(crate::emscripten_target::nullFunc_vijiii), "invoke_iiiii" => func!(crate::emscripten_target::invoke_iiiii),
"nullFunc_vijj" => func!(crate::emscripten_target::nullFunc_vijj), "invoke_iiiiii" => func!(crate::emscripten_target::invoke_iiiiii),
"invoke_dii" => func!(crate::emscripten_target::invoke_dii), "invoke_iiiiiii" => func!(crate::emscripten_target::invoke_iiiiiii),
"invoke_diiii" => func!(crate::emscripten_target::invoke_diiii), "invoke_iiiiiiii" => func!(crate::emscripten_target::invoke_iiiiiiii),
"invoke_iiiii" => func!(crate::emscripten_target::invoke_iiiii), "invoke_iiiiiiiii" => func!(crate::emscripten_target::invoke_iiiiiiiii),
"invoke_iiiiii" => func!(crate::emscripten_target::invoke_iiiiii), "invoke_iiiiiiiiii" => func!(crate::emscripten_target::invoke_iiiiiiiiii),
"invoke_vd" => func!(crate::emscripten_target::invoke_vd), "invoke_iiiiiiiiiii" => func!(crate::emscripten_target::invoke_iiiiiiiiiii),
"invoke_viiiii" => func!(crate::emscripten_target::invoke_viiiii), "invoke_vd" => func!(crate::emscripten_target::invoke_vd),
"invoke_viiiiii" => func!(crate::emscripten_target::invoke_viiiiii), "invoke_viiiii" => func!(crate::emscripten_target::invoke_viiiii),
"invoke_viiiiiii" => func!(crate::emscripten_target::invoke_viiiiiii), "invoke_viiiiii" => func!(crate::emscripten_target::invoke_viiiiii),
"invoke_viiiiiiii" => func!(crate::emscripten_target::invoke_viiiiiiii), "invoke_viiiiiii" => func!(crate::emscripten_target::invoke_viiiiiii),
"invoke_viiiiiiiii" => func!(crate::emscripten_target::invoke_viiiiiiiii), "invoke_viiiiiiii" => func!(crate::emscripten_target::invoke_viiiiiiii),
"invoke_iiji" => func!(crate::emscripten_target::invoke_iiji), "invoke_viiiiiiiii" => func!(crate::emscripten_target::invoke_viiiiiiiii),
"invoke_j" => func!(crate::emscripten_target::invoke_j), "invoke_viiiiiiiii" => func!(crate::emscripten_target::invoke_viiiiiiiii),
"invoke_ji" => func!(crate::emscripten_target::invoke_ji), "invoke_viiiiiiiiii" => func!(crate::emscripten_target::invoke_viiiiiiiiii),
"invoke_jij" => func!(crate::emscripten_target::invoke_jij), "invoke_iij" => func!(crate::emscripten_target::invoke_iij),
"invoke_jjj" => func!(crate::emscripten_target::invoke_jjj), "invoke_iiji" => func!(crate::emscripten_target::invoke_iiji),
"invoke_viiij" => func!(crate::emscripten_target::invoke_viiij), "invoke_iiijj" => func!(crate::emscripten_target::invoke_iiijj),
"invoke_viiijiiii" => func!(crate::emscripten_target::invoke_viiijiiii), "invoke_j" => func!(crate::emscripten_target::invoke_j),
"invoke_viiijiiiiii" => func!(crate::emscripten_target::invoke_viiijiiiiii), "invoke_ji" => func!(crate::emscripten_target::invoke_ji),
"invoke_viij" => func!(crate::emscripten_target::invoke_viij), "invoke_jii" => func!(crate::emscripten_target::invoke_jii),
"invoke_viiji" => func!(crate::emscripten_target::invoke_viiji), "invoke_jij" => func!(crate::emscripten_target::invoke_jij),
"invoke_viijiii" => func!(crate::emscripten_target::invoke_viijiii), "invoke_jjj" => func!(crate::emscripten_target::invoke_jjj),
"invoke_viijj" => func!(crate::emscripten_target::invoke_viijj), "invoke_viiij" => func!(crate::emscripten_target::invoke_viiij),
"invoke_vij" => func!(crate::emscripten_target::invoke_vij), "invoke_viiijiiii" => func!(crate::emscripten_target::invoke_viiijiiii),
"invoke_viji" => func!(crate::emscripten_target::invoke_viji), "invoke_viiijiiiiii" => func!(crate::emscripten_target::invoke_viiijiiiiii),
"invoke_vijiii" => func!(crate::emscripten_target::invoke_vijiii), "invoke_viij" => func!(crate::emscripten_target::invoke_viij),
"invoke_vijj" => func!(crate::emscripten_target::invoke_vijj), "invoke_viiji" => func!(crate::emscripten_target::invoke_viiji),
}, "invoke_viijiii" => func!(crate::emscripten_target::invoke_viijiii),
"invoke_viijj" => func!(crate::emscripten_target::invoke_viijj),
"invoke_vij" => func!(crate::emscripten_target::invoke_vij),
"invoke_viji" => func!(crate::emscripten_target::invoke_viji),
"invoke_vijiii" => func!(crate::emscripten_target::invoke_vijiii),
"invoke_vijj" => func!(crate::emscripten_target::invoke_vijj),
"invoke_viid" => func!(crate::emscripten_target::invoke_viid),
"invoke_viidii" => func!(crate::emscripten_target::invoke_viidii),
"invoke_viidddddddd" => func!(crate::emscripten_target::invoke_viidddddddd),
};
for null_func_name in globals.null_func_names.iter() {
env_ns.insert(null_func_name.as_str(), Func::new(nullfunc).to_export());
}
let import_object: ImportObject = imports! {
"env" => env_ns,
"global" => { "global" => {
"NaN" => Global::new(Value::F64(f64::NAN)), "NaN" => Global::new(Value::F64(f64::NAN)),
"Infinity" => Global::new(Value::F64(f64::INFINITY)), "Infinity" => Global::new(Value::F64(f64::INFINITY)),
}, },
"global.Math" => { "global.Math" => {
"pow" => func!(crate::math::pow), "pow" => func!(crate::math::pow),
"exp" => func!(crate::math::exp),
"log" => func!(crate::math::log),
}, },
"asm2wasm" => { "asm2wasm" => {
"f64-rem" => func!(crate::math::f64_rem), "f64-rem" => func!(crate::math::f64_rem),
"f64-to-int" => func!(crate::math::f64_to_int),
}, },
} };
import_object
}
pub fn nullfunc(ctx: &mut Ctx, _x: u32) {
use crate::process::abort_with_message;
debug!("emscripten::nullfunc_i {}", _x);
abort_with_message(ctx, "Invalid function pointer. Perhaps this is an invalid value \
(e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an \
incorrect type, which will fail? (it is worth building your source files with -Werror (\
warnings are errors), as warnings can indicate undefined behavior which can cause this)");
} }
/// The current version of this crate /// The current version of this crate

View File

@ -2,16 +2,21 @@ use libc::c_int;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
// NOTE: Not implemented by Emscripten // NOTE: Not implemented by Emscripten
pub fn ___lock(_ctx: &mut Ctx, what: c_int) { pub fn ___lock(_ctx: &mut Ctx, _what: c_int) {
debug!("emscripten::___lock {}", what); debug!("emscripten::___lock {}", _what);
} }
// NOTE: Not implemented by Emscripten // NOTE: Not implemented by Emscripten
pub fn ___unlock(_ctx: &mut Ctx, what: c_int) { pub fn ___unlock(_ctx: &mut Ctx, _what: c_int) {
debug!("emscripten::___unlock {}", what); debug!("emscripten::___unlock {}", _what);
} }
// NOTE: Not implemented by Emscripten // NOTE: Not implemented by Emscripten
pub fn ___wait(_ctx: &mut Ctx, _which: u32, _varargs: u32, _three: u32, _four: u32) { pub fn ___wait(_ctx: &mut Ctx, _which: u32, _varargs: u32, _three: u32, _four: u32) {
debug!("emscripten::___wait"); debug!("emscripten::___wait");
} }
pub fn _flock(_ctx: &mut Ctx, _fd: u32, _op: u32) -> u32 {
debug!("emscripten::_flock");
0
}

View File

@ -12,6 +12,18 @@ pub fn _llvm_log2_f64(_ctx: &mut Ctx, value: f64) -> f64 {
value.log2() value.log2()
} }
/// emscripten: _llvm_sin_f64
pub fn _llvm_sin_f64(_ctx: &mut Ctx, value: f64) -> f64 {
debug!("emscripten::_llvm_sin_f64");
value.sin()
}
/// emscripten: _llvm_cos_f64
pub fn _llvm_cos_f64(_ctx: &mut Ctx, value: f64) -> f64 {
debug!("emscripten::_llvm_cos_f64");
value.cos()
}
pub fn _llvm_log10_f32(_ctx: &mut Ctx, _value: f64) -> f64 { pub fn _llvm_log10_f32(_ctx: &mut Ctx, _value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f32"); debug!("emscripten::_llvm_log10_f32");
-1.0 -1.0
@ -22,12 +34,22 @@ pub fn _llvm_log2_f32(_ctx: &mut Ctx, _value: f64) -> f64 {
-1.0 -1.0
} }
pub fn _llvm_exp2_f32(_ctx: &mut Ctx, value: f32) -> f32 {
debug!("emscripten::_llvm_exp2_f32");
2f32.powf(value)
}
pub fn _llvm_exp2_f64(_ctx: &mut Ctx, value: f64) -> f64 {
debug!("emscripten::_llvm_exp2_f64");
2f64.powf(value)
}
pub fn _emscripten_random(_ctx: &mut Ctx) -> f64 { pub fn _emscripten_random(_ctx: &mut Ctx) -> f64 {
debug!("emscripten::_emscripten_random"); debug!("emscripten::_emscripten_random");
-1.0 -1.0
} }
// emscripten: f64-rem // emscripten: asm2wasm.f64-rem
pub fn f64_rem(_ctx: &mut Ctx, x: f64, y: f64) -> f64 { pub fn f64_rem(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
debug!("emscripten::f64-rem"); debug!("emscripten::f64-rem");
x % y x % y
@ -37,3 +59,19 @@ pub fn f64_rem(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
pub fn pow(_ctx: &mut Ctx, x: f64, y: f64) -> f64 { pub fn pow(_ctx: &mut Ctx, x: f64, y: f64) -> f64 {
x.powf(y) x.powf(y)
} }
// emscripten: global.Math exp
pub fn exp(_ctx: &mut Ctx, value: f64) -> f64 {
value.exp()
}
// emscripten: global.Math log
pub fn log(_ctx: &mut Ctx, value: f64) -> f64 {
value.ln()
}
// emscripten: asm2wasm.f64-to-int
pub fn f64_to_int(_ctx: &mut Ctx, value: f64) -> i32 {
debug!("emscripten::f64_to_int {}", value);
value as i32
}

View File

@ -1,6 +1,9 @@
use super::process::abort_with_message; use super::process::abort_with_message;
use libc::{c_int, c_void, memcpy, size_t}; use libc::{c_int, c_void, memcpy, size_t};
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::{
units::{Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE},
vm::Ctx,
};
/// emscripten: _emscripten_memcpy_big /// emscripten: _emscripten_memcpy_big
pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u32 { pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u32 {
@ -19,15 +22,44 @@ pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u
/// emscripten: _emscripten_get_heap_size /// emscripten: _emscripten_get_heap_size
pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 { pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 {
debug!("emscripten::_emscripten_get_heap_size",); debug!("emscripten::_emscripten_get_heap_size",);
// TODO: Fix implementation ctx.memory(0).size().bytes().0 as u32
16_777_216 }
// From emscripten implementation
fn align_up(mut val: usize, multiple: usize) -> usize {
if val % multiple > 0 {
val += multiple - val % multiple;
}
val
} }
/// emscripten: _emscripten_resize_heap /// emscripten: _emscripten_resize_heap
/// Note: this function only allows growing the size of heap
pub fn _emscripten_resize_heap(ctx: &mut Ctx, requested_size: u32) -> u32 { pub fn _emscripten_resize_heap(ctx: &mut Ctx, requested_size: u32) -> u32 {
debug!("emscripten::_emscripten_resize_heap {}", requested_size); debug!("emscripten::_emscripten_resize_heap {}", requested_size);
// TODO: Fix implementation let current_memory_pages = ctx.memory(0).size();
0 let current_memory = current_memory_pages.bytes().0 as u32;
// implementation from emscripten
let mut new_size = usize::max(current_memory as usize, WASM_MIN_PAGES * WASM_PAGE_SIZE);
while new_size < requested_size as usize {
if new_size <= 0x2000_0000 {
new_size = align_up(new_size * 2, WASM_PAGE_SIZE);
} else {
new_size = usize::min(
align_up((3 * new_size + 0x8000_0000) / 4, WASM_PAGE_SIZE),
WASM_PAGE_SIZE * WASM_MAX_PAGES,
);
}
}
let amount_to_grow = (new_size - current_memory as usize) / WASM_PAGE_SIZE;
if let Ok(_pages_allocated) = ctx.memory(0).grow(Pages(amount_to_grow as u32)) {
debug!("{} pages allocated", _pages_allocated.0);
1
} else {
0
}
} }
/// emscripten: getTotalMemory /// emscripten: getTotalMemory
@ -35,7 +67,7 @@ pub fn get_total_memory(_ctx: &mut Ctx) -> u32 {
debug!("emscripten::get_total_memory"); debug!("emscripten::get_total_memory");
// instance.memories[0].current_pages() // instance.memories[0].current_pages()
// TODO: Fix implementation // TODO: Fix implementation
16_777_216 _ctx.memory(0).size().bytes().0 as u32
} }
/// emscripten: enlargeMemory /// emscripten: enlargeMemory
@ -47,8 +79,11 @@ pub fn enlarge_memory(_ctx: &mut Ctx) -> u32 {
} }
/// emscripten: abortOnCannotGrowMemory /// emscripten: abortOnCannotGrowMemory
pub fn abort_on_cannot_grow_memory(ctx: &mut Ctx, requested_size: u32) -> u32 { pub fn abort_on_cannot_grow_memory(ctx: &mut Ctx, _requested_size: u32) -> u32 {
debug!("emscripten::abort_on_cannot_grow_memory {}", requested_size); debug!(
"emscripten::abort_on_cannot_grow_memory {}",
_requested_size
);
abort_with_message(ctx, "Cannot enlarge memory arrays!"); abort_with_message(ctx, "Cannot enlarge memory arrays!");
0 0
} }

View File

@ -1,67 +0,0 @@
use super::process::abort_with_message;
use wasmer_runtime_core::vm::Ctx;
pub fn nullfunc_i(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_i {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'i'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_ii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_ii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'ii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_iii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'iii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_iiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iiii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'iiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_iiiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iiiii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'iiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_iiiiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_iiiiii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'iiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_v(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_v {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'v'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_vi(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_vi {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'vi'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_vii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_vii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'vii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_viii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_viii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'viii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_viiii(ctx: &mut Ctx, x: u32) {
debug!("emscripten::nullfunc_viiii {}", x);
abort_with_message(ctx, "Invalid function pointer called with signature 'viiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_viiiii(ctx: &mut Ctx, _x: u32) {
debug!("emscripten::nullfunc_viiiii");
abort_with_message(ctx, "Invalid function pointer called with signature 'viiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub fn nullfunc_viiiiii(ctx: &mut Ctx, _x: u32) {
debug!("emscripten::nullfunc_viiiiii");
abort_with_message(ctx, "Invalid function pointer called with signature 'viiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}

View File

@ -1,10 +1,9 @@
use libc::{abort, c_char, c_int, exit, EAGAIN}; use libc::{abort, c_char, c_int, exit, EAGAIN};
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
use libc::pid_t; type PidT = libc::pid_t;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
type pid_t = c_int; type PidT = c_int;
use std::ffi::CStr; use std::ffi::CStr;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
@ -22,7 +21,7 @@ pub fn _abort(_ctx: &mut Ctx) {
} }
} }
pub fn _fork(_ctx: &mut Ctx) -> pid_t { pub fn _fork(_ctx: &mut Ctx) -> PidT {
debug!("emscripten::_fork"); debug!("emscripten::_fork");
// unsafe { // unsafe {
// fork() // fork()
@ -98,7 +97,7 @@ pub fn _sem_wait(_ctx: &mut Ctx, _one: i32) -> i32 {
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn _getgrent(ctx: &mut Ctx) -> c_int { pub fn _getgrent(_ctx: &mut Ctx) -> c_int {
debug!("emscripten::_getgrent"); debug!("emscripten::_getgrent");
-1 -1
} }
@ -122,6 +121,11 @@ pub fn _usleep(_ctx: &mut Ctx, _one: i32) -> i32 {
-1 -1
} }
pub fn _nanosleep(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_nanosleep");
-1
}
pub fn _utimes(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn _utimes(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::_utimes"); debug!("emscripten::_utimes");
-1 -1
@ -146,6 +150,11 @@ pub fn _llvm_trap(ctx: &mut Ctx) {
abort_with_message(ctx, "abort!"); abort_with_message(ctx, "abort!");
} }
pub fn _llvm_eh_typeid_for(_ctx: &mut Ctx, _type_info_addr: u32) -> i32 {
debug!("emscripten::_llvm_eh_typeid_for");
-1
}
pub fn _system(_ctx: &mut Ctx, _one: i32) -> c_int { pub fn _system(_ctx: &mut Ctx, _one: i32) -> c_int {
debug!("emscripten::_system"); debug!("emscripten::_system");
// TODO: May need to change this Em impl to a working version // TODO: May need to change this Em impl to a working version

View File

@ -11,8 +11,8 @@ pub fn _sigemptyset(ctx: &mut Ctx, set: u32) -> i32 {
0 0
} }
pub fn _sigaction(_ctx: &mut Ctx, signum: u32, act: u32, oldact: u32) -> i32 { pub fn _sigaction(_ctx: &mut Ctx, _signum: u32, _act: u32, _oldact: u32) -> i32 {
debug!("emscripten::_sigaction {}, {}, {}", signum, act, oldact); debug!("emscripten::_sigaction {}, {}, {}", _signum, _act, _oldact);
0 0
} }
@ -36,7 +36,7 @@ pub fn _sigprocmask(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
0 0
} }
pub fn _signal(_ctx: &mut Ctx, sig: u32, _two: i32) -> i32 { pub fn _signal(_ctx: &mut Ctx, _sig: u32, _two: i32) -> i32 {
debug!("emscripten::_signal ({})", sig); debug!("emscripten::_signal ({})", _sig);
0 0
} }

View File

@ -15,7 +15,7 @@ pub struct StdioCapturer {
use libc::{STDERR_FILENO, STDOUT_FILENO}; use libc::{STDERR_FILENO, STDOUT_FILENO};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
const STDIN_FILENO: libc::c_int = 0; const _STDIN_FILENO: libc::c_int = 0;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
const STDOUT_FILENO: libc::c_int = 1; const STDOUT_FILENO: libc::c_int = 1;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]

View File

@ -28,6 +28,7 @@ use libc::{
getpid, getpid,
// iovec, // iovec,
lseek, lseek,
off_t,
// open, // open,
read, read,
// readv, // readv,
@ -40,20 +41,15 @@ use libc::{
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
use super::env; use super::env;
use std::cell::Cell;
#[allow(unused_imports)]
use std::io::Error;
use std::mem;
use std::slice; use std::slice;
// use std::sys::fd::FileDesc;
// Another conditional constant for name resolution: Macos et iOS use
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
// Other platforms do otherwise.
#[cfg(target_os = "darwin")]
use libc::SO_NOSIGPIPE;
#[cfg(not(target_os = "darwin"))]
const SO_NOSIGPIPE: c_int = 0;
/// exit /// exit
pub fn ___syscall1(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) { pub fn ___syscall1(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) {
debug!("emscripten::___syscall1 (exit) {}", which); debug!("emscripten::___syscall1 (exit) {}", _which);
let status: i32 = varargs.get(ctx); let status: i32 = varargs.get(ctx);
unsafe { unsafe {
exit(status); exit(status);
@ -61,47 +57,47 @@ pub fn ___syscall1(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) {
} }
/// read /// read
pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 { pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
// -> ssize_t // -> ssize_t
debug!("emscripten::___syscall3 (read) {}", which); debug!("emscripten::___syscall3 (read) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
let count = varargs.get(ctx); let count: i32 = varargs.get(ctx);
debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void; let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void;
let ret = unsafe { read(fd, buf_addr, count) }; let ret = unsafe { read(fd, buf_addr, count as _) };
debug!("=> ret: {}", ret); debug!("=> ret: {}", ret);
ret as _ ret as _
} }
/// write /// write
pub fn ___syscall4(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall4 (write) {}", which); debug!("emscripten::___syscall4 (write) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
let count = varargs.get(ctx); let count: i32 = varargs.get(ctx);
debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count); debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void; let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void;
unsafe { write(fd, buf_addr, count) as i32 } unsafe { write(fd, buf_addr, count as _) as i32 }
} }
/// close /// close
pub fn ___syscall6(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall6 (close) {}", which); debug!("emscripten::___syscall6 (close) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
debug!("fd: {}", fd); debug!("fd: {}", fd);
unsafe { close(fd) } unsafe { close(fd) }
} }
// chdir // chdir
pub fn ___syscall12(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall12 (chdir) {}", which); debug!("emscripten::___syscall12 (chdir) {}", _which);
let path_addr: i32 = varargs.get(ctx); let path_addr: i32 = varargs.get(ctx);
unsafe { unsafe {
let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path_addr) as *const i8; let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path_addr) as *const i8;
let path = std::ffi::CStr::from_ptr(path_ptr); let _path = std::ffi::CStr::from_ptr(path_ptr);
let ret = chdir(path_ptr); let ret = chdir(path_ptr);
debug!("=> path: {:?}, ret: {}", path, ret); debug!("=> path: {:?}, ret: {}", _path, ret);
ret ret
} }
} }
@ -135,14 +131,40 @@ pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
unsafe { rmdir(pathname_addr) } unsafe { rmdir(pathname_addr) }
} }
// pipe
pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall42 (pipe)");
// offset to a file descriptor, which contains a read end and write end, 2 integers
let fd_offset: u32 = varargs.get(ctx);
let emscripten_memory = ctx.memory(0);
// convert the file descriptor into a vec with two slots
let mut fd_vec: Vec<c_int> = emscripten_memory.view()[((fd_offset / 4) as usize)..]
.iter()
.map(|pipe_end: &Cell<c_int>| pipe_end.get())
.take(2)
.collect();
// get it as a mutable pointer
let fd_ptr = fd_vec.as_mut_ptr();
// call pipe and store the pointers in this array
#[cfg(target_os = "windows")]
let result: c_int = unsafe { libc::pipe(fd_ptr, 2048, 0) };
#[cfg(not(target_os = "windows"))]
let result: c_int = unsafe { libc::pipe(fd_ptr) };
result
}
pub fn ___syscall60(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn ___syscall60(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall60"); debug!("emscripten::___syscall60");
-1 -1
} }
// dup2 // dup2
pub fn ___syscall63(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall63 (dup2) {}", which); debug!("emscripten::___syscall63 (dup2) {}", _which);
let src: i32 = varargs.get(ctx); let src: i32 = varargs.get(ctx);
let dst: i32 = varargs.get(ctx); let dst: i32 = varargs.get(ctx);
@ -172,8 +194,8 @@ pub fn ___syscall85(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
} }
pub fn ___syscall91(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn ___syscall91(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall91"); debug!("emscripten::___syscall91 - stub");
-1 0
} }
pub fn ___syscall97(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn ___syscall97(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
@ -186,18 +208,39 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1 -1
} }
// getcwd
pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall183");
use std::env;
let buf_offset: c_int = varargs.get(ctx);
let _size: c_int = varargs.get(ctx);
let path = env::current_dir();
let path_string = path.unwrap().display().to_string();
let len = path_string.len();
unsafe {
let pointer_to_buffer =
emscripten_memory_pointer!(ctx.memory(0), buf_offset) as *mut libc::c_char;
let slice = slice::from_raw_parts_mut(pointer_to_buffer, len.clone());
for (byte, loc) in path_string.bytes().zip(slice.iter_mut()) {
*loc = byte as _;
}
*pointer_to_buffer.add(len.clone()) = 0;
}
buf_offset
}
// mmap2 // mmap2
pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall192(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall192 (mmap2) {}", which); debug!("emscripten::___syscall192 (mmap2) {}", _which);
let addr: i32 = varargs.get(ctx); let _addr: i32 = varargs.get(ctx);
let len: u32 = varargs.get(ctx); let len: u32 = varargs.get(ctx);
let prot: i32 = varargs.get(ctx); let _prot: i32 = varargs.get(ctx);
let flags: i32 = varargs.get(ctx); let _flags: i32 = varargs.get(ctx);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let off: i32 = varargs.get(ctx); let _off: i32 = varargs.get(ctx);
debug!( debug!(
"=> addr: {}, len: {}, prot: {}, flags: {}, fd: {}, off: {}", "=> addr: {}, len: {}, prot: {}, flags: {}, fd: {}, off: {}",
addr, len, prot, flags, fd, off _addr, len, _prot, _flags, fd, _off
); );
if fd == -1 { if fd == -1 {
@ -213,27 +256,39 @@ pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
} }
/// lseek /// lseek
pub fn ___syscall140(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 { pub fn ___syscall140(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
// -> c_int // -> c_int
debug!("emscripten::___syscall140 (lseek) {}", which); debug!("emscripten::___syscall140 (lseek) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let offset = varargs.get(ctx); let _ = varargs.get::<i32>(ctx); // ignore high offset
let offset_low: i32 = varargs.get(ctx);
let result_ptr_value = varargs.get::<i32>(ctx);
let whence: i32 = varargs.get(ctx); let whence: i32 = varargs.get(ctx);
debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence); let offset = offset_low as off_t;
unsafe { lseek(fd, offset, whence) as _ } let ret = unsafe { lseek(fd, offset, whence) as i32 };
#[allow(clippy::cast_ptr_alignment)]
let result_ptr = emscripten_memory_pointer!(ctx.memory(0), result_ptr_value) as *mut i32;
assert_eq!(8, mem::align_of_val(&result_ptr));
unsafe {
*result_ptr = ret;
}
debug!(
"=> fd: {}, offset: {}, result_ptr: {}, whence: {} = {}\nlast os error: {}",
fd,
offset,
result_ptr_value,
whence,
0,
Error::last_os_error(),
);
0
} }
/// readv /// readv
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall145(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> i32 { pub fn ___syscall145(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
// -> ssize_t // -> ssize_t
debug!("emscripten::___syscall145 (readv) {}", which); debug!("emscripten::___syscall145 (readv) {}", _which);
// let fd: i32 = varargs.get(ctx);
// let iov: u32 = varargs.get(ctx);
// let iovcnt: i32 = varargs.get(ctx);
// debug!("=> fd: {}, iov: {}, iovcnt = {}", fd, iov, iovcnt);
// let iov_addr = emscripten_memory_pointer!(ctx.memory(0), iov) as *mut iovec;
// unsafe { readv(fd, iov_addr, iovcnt) }
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let iov: i32 = varargs.get(ctx); let iov: i32 = varargs.get(ctx);
@ -268,9 +323,9 @@ pub fn ___syscall145(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> i32 {
// writev // writev
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall146(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 { pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
// -> ssize_t // -> ssize_t
debug!("emscripten::___syscall146 (writev) {}", which); debug!("emscripten::___syscall146 (writev) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let iov: i32 = varargs.get(ctx); let iov: i32 = varargs.get(ctx);
let iovcnt: i32 = varargs.get(ctx); let iovcnt: i32 = varargs.get(ctx);
@ -312,24 +367,14 @@ pub fn ___syscall191(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1 -1
} }
pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall194 - stub");
-1
}
pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall194 - stub");
-1
}
pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall199 - stub"); debug!("emscripten::___syscall199 - stub");
-1 -1
} }
// stat64 // stat64
pub fn ___syscall195(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall195 (stat64) {}", which); debug!("emscripten::___syscall195 (stat64) {}", _which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
@ -338,7 +383,14 @@ pub fn ___syscall195(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
unsafe { unsafe {
let mut _stat: stat = std::mem::zeroed(); let mut _stat: stat = std::mem::zeroed();
let ret = stat(pathname_addr, &mut _stat); let ret = stat(pathname_addr, &mut _stat);
debug!("ret: {}", ret); debug!(
"=> pathname: {}, buf: {}, path: {} = {}\nlast os error: {}",
pathname,
buf,
std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap(),
ret,
Error::last_os_error()
);
if ret != 0 { if ret != 0 {
return ret; return ret;
} }
@ -348,8 +400,8 @@ pub fn ___syscall195(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
} }
// fstat64 // fstat64
pub fn ___syscall197(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall197 (fstat64) {}", which); debug!("emscripten::___syscall197 (fstat64) {}", _which);
let fd: c_int = varargs.get(ctx); let fd: c_int = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
@ -372,13 +424,19 @@ pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
} }
// fcntl64 // fcntl64
pub fn ___syscall221(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall221 (fcntl64) {}", which); debug!("emscripten::___syscall221 (fcntl64) {}", _which);
// fcntl64 // fcntl64
let _fd: i32 = varargs.get(ctx); let _fd: i32 = varargs.get(ctx);
let cmd: u32 = varargs.get(ctx); let cmd: u32 = varargs.get(ctx);
// (FAPPEND - 0x08
// |FASYNC - 0x40
// |FFSYNC - 0x80
// |FNONBLOCK - 0x04
debug!("=> fd: {}, cmd: {}", _fd, cmd);
match cmd { match cmd {
2 => 0, 2 => 0,
13 | 14 => 0, // pretend file locking worked
_ => -1, _ => -1,
} }
} }
@ -409,8 +467,8 @@ pub fn ___syscall334(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
} }
// prlimit64 // prlimit64
pub fn ___syscall340(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall340(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall340 (prlimit64), {}", which); debug!("emscripten::___syscall340 (prlimit64), {}", _which);
// NOTE: Doesn't really matter. Wasm modules cannot exceed WASM_PAGE_SIZE anyway. // NOTE: Doesn't really matter. Wasm modules cannot exceed WASM_PAGE_SIZE anyway.
let _pid: i32 = varargs.get(ctx); let _pid: i32 = varargs.get(ctx);
let _resource: i32 = varargs.get(ctx); let _resource: i32 = varargs.get(ctx);

View File

@ -3,27 +3,40 @@ use crate::varargs::VarArgs;
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html /// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
use libc::{ use libc::{
accept, accept,
access,
bind, bind,
// ENOTTY,
c_char, c_char,
c_int, c_int,
c_void, c_void,
chown, chown,
// fcntl, setsockopt, getppid // fcntl, setsockopt, getppid
connect, connect,
dup,
dup2, dup2,
fchmod,
fchown,
fcntl, fcntl,
// ENOTTY,
fsync,
getgid, getgid,
getgroups,
getpeername, getpeername,
getrusage,
getsockname, getsockname,
getsockopt, getsockopt,
gid_t,
in_addr_t, in_addr_t,
in_port_t, in_port_t,
ioctl, ioctl,
lchown,
link,
// iovec, // iovec,
listen, listen,
mkdir, mkdir,
mode_t,
msghdr, msghdr,
nice,
off_t,
open, open,
pid_t, pid_t,
pread, pread,
@ -40,9 +53,13 @@ use libc::{
sendto, sendto,
setpgid, setpgid,
setsockopt, setsockopt,
size_t,
sockaddr, sockaddr,
socket, socket,
socklen_t, socklen_t,
stat,
symlink,
uid_t,
uname, uname,
utsname, utsname,
EINVAL, EINVAL,
@ -57,6 +74,9 @@ use libc::{
}; };
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
use crate::utils;
#[allow(unused_imports)]
use std::io::Error;
use std::mem; use std::mem;
// Linking to functions that are not provided by rust libc // Linking to functions that are not provided by rust libc
@ -64,10 +84,13 @@ use std::mem;
#[link(name = "c")] #[link(name = "c")]
extern "C" { extern "C" {
pub fn wait4(pid: pid_t, status: *mut c_int, options: c_int, rusage: *mut rusage) -> pid_t; pub fn wait4(pid: pid_t, status: *mut c_int, options: c_int, rusage: *mut rusage) -> pid_t;
pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int;
pub fn fdatasync(fd: c_int) -> c_int;
pub fn lstat64(path: *const c_char, buf: *mut c_void) -> c_int;
} }
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
use libc::wait4; use libc::{fallocate, fdatasync, ftruncate64, lstat, madvise, wait4};
// Another conditional constant for name resolution: Macos et iOS use // Another conditional constant for name resolution: Macos et iOS use
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. // SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
@ -78,24 +101,125 @@ use libc::SO_NOSIGPIPE;
const SO_NOSIGPIPE: c_int = 0; const SO_NOSIGPIPE: c_int = 0;
/// open /// open
pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall5 (open) {}", which); debug!("emscripten::___syscall5 (open) {}", _which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let flags: i32 = varargs.get(ctx); let flags: i32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx);
let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8;
let path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() }; let _path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() };
let fd = unsafe { open(pathname_addr, flags, mode) }; let fd = unsafe { open(pathname_addr, flags, mode) };
debug!( debug!(
"=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}", "=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}\nlast os error: {}",
pathname, flags, mode, fd, path_str pathname,
flags,
mode,
fd,
_path_str,
Error::last_os_error(),
); );
fd fd
} }
/// link
pub fn ___syscall9(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall9 (link) {}", _which);
let oldname: c_int = varargs.get(ctx);
let newname: c_int = varargs.get(ctx);
let oldname_ptr = emscripten_memory_pointer!(ctx.memory(0), oldname) as *const i8;
let newname_ptr = emscripten_memory_pointer!(ctx.memory(0), newname) as *const i8;
let result = unsafe { link(oldname_ptr, newname_ptr) };
debug!(
"=> oldname: {}, newname: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(oldname_ptr).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(newname_ptr).to_str().unwrap() },
result,
);
result
}
/// getrusage
pub fn ___syscall77(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall77 (getrusage) {}", _which);
let resource: c_int = varargs.get(ctx);
let rusage_ptr: c_int = varargs.get(ctx);
#[allow(clippy::cast_ptr_alignment)]
let rusage = emscripten_memory_pointer!(ctx.memory(0), rusage_ptr) as *mut rusage;
assert_eq!(8, mem::align_of_val(&rusage));
unsafe { getrusage(resource, rusage) }
}
/// symlink
pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall83 (symlink) {}", _which);
let path1_ptr: c_int = varargs.get(ctx);
let path2_ptr: c_int = varargs.get(ctx);
let path1 = emscripten_memory_pointer!(ctx.memory(0), path1_ptr) as *mut i8;
let path2 = emscripten_memory_pointer!(ctx.memory(0), path2_ptr) as *mut i8;
let result = unsafe { symlink(path1, path2) };
debug!(
"=> path1: {}, path2: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path1).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(path2).to_str().unwrap() },
result,
);
result
}
/// ftruncate64
pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall194 (ftruncate64) {}", _which);
let _fd: c_int = varargs.get(ctx);
let _length: i64 = varargs.get(ctx);
#[cfg(not(target_os = "macos"))]
unsafe {
ftruncate64(_fd, _length)
}
#[cfg(target_os = "macos")]
unimplemented!()
}
/// lchown
pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall198 (lchown) {}", _which);
let path: c_int = varargs.get(ctx);
let uid: uid_t = varargs.get(ctx);
let gid: gid_t = varargs.get(ctx);
let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path) as *const i8;
let result = unsafe { lchown(path_ptr, uid, gid) };
debug!(
"=> path: {}, uid: {}, gid: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path_ptr).to_str().unwrap() },
uid,
gid,
result,
);
result
}
/// getgroups
pub fn ___syscall205(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall205 (getgroups) {}", _which);
let ngroups_max: c_int = varargs.get(ctx);
let groups: c_int = varargs.get(ctx);
#[allow(clippy::cast_ptr_alignment)]
let gid_ptr = emscripten_memory_pointer!(ctx.memory(0), groups) as *mut gid_t;
assert_eq!(4, mem::align_of_val(&gid_ptr));
let result = unsafe { getgroups(ngroups_max, gid_ptr) };
debug!(
"=> ngroups_max: {}, gid_ptr: {:?}, result: {}",
ngroups_max, gid_ptr, result,
);
result
}
// chown // chown
pub fn ___syscall212(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", which); debug!("emscripten::___syscall212 (chown) {}", _which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let owner: u32 = varargs.get(ctx); let owner: u32 = varargs.get(ctx);
@ -106,15 +230,63 @@ pub fn ___syscall212(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
unsafe { chown(pathname_addr, owner, group) } unsafe { chown(pathname_addr, owner, group) }
} }
/// madvise
pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", _which);
let addr_ptr: c_int = varargs.get(ctx);
let len: usize = varargs.get(ctx);
let advice: c_int = varargs.get(ctx);
let addr = emscripten_memory_pointer!(ctx.memory(0), addr_ptr) as *mut c_void;
unsafe { madvise(addr, len, advice) }
}
/// access
pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall33 (access) {}", _which);
let path_ptr: c_int = varargs.get(ctx);
let amode: c_int = varargs.get(ctx);
let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8;
let result = unsafe { access(path, amode) };
debug!(
"=> path: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() },
result
);
result
}
/// nice
pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall34 (nice) {}", _which);
let inc_r: c_int = varargs.get(ctx);
unsafe { nice(inc_r) }
}
// mkdir // mkdir
pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", which); debug!("emscripten::___syscall39 (mkdir) {}", _which);
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx);
let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8;
unsafe { mkdir(pathname_addr, mode as _) } unsafe { mkdir(pathname_addr, mode as _) }
} }
/// dup
pub fn ___syscall41(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall41 (dup) {}", _which);
let fd: c_int = varargs.get(ctx);
unsafe { dup(fd) }
}
/// getgid
pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall200 (getgid)");
unsafe { getgid() as i32 }
}
// getgid // getgid
pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall201 (getgid)"); debug!("emscripten::___syscall201 (getgid)");
@ -134,6 +306,15 @@ pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
} }
} }
/// fchown
pub fn ___syscall207(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall207 (fchown) {}", _which);
let fd: c_int = varargs.get(ctx);
let owner: uid_t = varargs.get(ctx);
let group: gid_t = varargs.get(ctx);
unsafe { fchown(fd, owner, group) }
}
/// dup3 /// dup3
pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
// Implementation based on description at https://linux.die.net/man/2/dup3 // Implementation based on description at https://linux.die.net/man/2/dup3
@ -169,8 +350,8 @@ pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_
} }
/// ioctl /// ioctl
pub fn ___syscall54(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall54 (ioctl) {}", which); debug!("emscripten::___syscall54 (ioctl) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let request: u32 = varargs.get(ctx); let request: u32 = varargs.get(ctx);
debug!("fd: {}, op: {}", fd, request); debug!("fd: {}, op: {}", fd, request);
@ -212,8 +393,8 @@ pub fn ___syscall54(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
// socketcall // socketcall
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall102(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall102 (socketcall) {}", which); debug!("emscripten::___syscall102 (socketcall) {}", _which);
let call: u32 = varargs.get(ctx); let call: u32 = varargs.get(ctx);
let mut socket_varargs: VarArgs = varargs.get(ctx); let mut socket_varargs: VarArgs = varargs.get(ctx);
@ -279,13 +460,11 @@ pub fn ___syscall102(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr;
// Debug received address // Debug received address
unsafe { let _proper_address = address as *const GuestSockaddrIn;
let proper_address = address as *const GuestSockaddrIn; debug!(
debug!(
"=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}", "=> address.sin_family: {:?}, address.sin_port: {:?}, address.sin_addr.s_addr: {:?}",
(*proper_address).sin_family, (*proper_address).sin_port, (*proper_address).sin_addr.s_addr unsafe { (*_proper_address).sin_family }, unsafe { (*_proper_address).sin_port }, unsafe { (*_proper_address).sin_addr.s_addr }
); );
}
let status = unsafe { bind(socket, address, address_len) }; let status = unsafe { bind(socket, address, address_len) };
// debug!("=> status: {}", status); // debug!("=> status: {}", status);
@ -464,8 +643,8 @@ pub fn ___syscall102(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
} }
// pread // pread
pub fn ___syscall180(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall180 (pread) {}", which); debug!("emscripten::___syscall180 (pread) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
let count: u32 = varargs.get(ctx); let count: u32 = varargs.get(ctx);
@ -481,8 +660,8 @@ pub fn ___syscall180(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
} }
// pwrite // pwrite
pub fn ___syscall181(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall181(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall181 (pwrite) {}", which); debug!("emscripten::___syscall181 (pwrite) {}", _which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
let count: u32 = varargs.get(ctx); let count: u32 = varargs.get(ctx);
@ -501,6 +680,14 @@ pub fn ___syscall181(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
status status
} }
/// fchmod
pub fn ___syscall94(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fchmod) {}", _which);
let fd: c_int = varargs.get(ctx);
let mode: mode_t = varargs.get(ctx);
unsafe { fchmod(fd, mode) }
}
/// wait4 /// wait4
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t {
@ -510,6 +697,7 @@ pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_
let options: c_int = varargs.get(ctx); let options: c_int = varargs.get(ctx);
let rusage: u32 = varargs.get(ctx); let rusage: u32 = varargs.get(ctx);
let status_addr = emscripten_memory_pointer!(ctx.memory(0), status) as *mut c_int; let status_addr = emscripten_memory_pointer!(ctx.memory(0), status) as *mut c_int;
let rusage_addr = emscripten_memory_pointer!(ctx.memory(0), rusage) as *mut rusage; let rusage_addr = emscripten_memory_pointer!(ctx.memory(0), rusage) as *mut rusage;
let res = unsafe { wait4(pid, status_addr, options, rusage_addr) }; let res = unsafe { wait4(pid, status_addr, options, rusage_addr) };
debug!( debug!(
@ -519,10 +707,17 @@ pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_
res res
} }
/// fsync
pub fn ___syscall118(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fsync) {}", _which);
let fd: c_int = varargs.get(ctx);
unsafe { fsync(fd) }
}
// select // select
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall142(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall142(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall142 (newselect) {}", which); debug!("emscripten::___syscall142 (newselect) {}", _which);
let nfds: i32 = varargs.get(ctx); let nfds: i32 = varargs.get(ctx);
let readfds: u32 = varargs.get(ctx); let readfds: u32 = varargs.get(ctx);
@ -539,9 +734,18 @@ pub fn ___syscall142(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
unsafe { select(nfds, readfds_ptr, writefds_ptr, 0 as _, 0 as _) } unsafe { select(nfds, readfds_ptr, writefds_ptr, 0 as _, 0 as _) }
} }
/// fdatasync
pub fn ___syscall148(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall148 (fdatasync) {}", _which);
let fd: i32 = varargs.get(ctx);
unsafe { fdatasync(fd) }
}
// setpgid // setpgid
pub fn ___syscall57(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall57(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall57 (setpgid) {}", which); debug!("emscripten::___syscall57 (setpgid) {}", _which);
let pid: i32 = varargs.get(ctx); let pid: i32 = varargs.get(ctx);
let pgid: i32 = varargs.get(ctx); let pgid: i32 = varargs.get(ctx);
unsafe { setpgid(pid, pgid) } unsafe { setpgid(pid, pgid) }
@ -549,10 +753,55 @@ pub fn ___syscall57(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
/// uname /// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten. // NOTE: Wondering if we should return custom utsname, like Emscripten.
pub fn ___syscall122(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall122 (uname) {}", which); debug!("emscripten::___syscall122 (uname) {}", _which);
let buf: u32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx);
debug!("=> buf: {}", buf); debug!("=> buf: {}", buf);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut utsname; let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut utsname;
unsafe { uname(buf_addr) } unsafe { uname(buf_addr) }
} }
/// lstat64
pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall196 (lstat64) {}", _which);
let path_ptr: c_int = varargs.get(ctx);
let buf_ptr: u32 = varargs.get(ctx);
let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8;
unsafe {
let mut stat: stat = std::mem::zeroed();
#[cfg(target_os = "macos")]
let stat_ptr = &mut stat as *mut stat as *mut c_void;
#[cfg(not(target_os = "macos"))]
let stat_ptr = &mut stat as *mut stat;
#[cfg(target_os = "macos")]
let ret = lstat64(path, stat_ptr);
#[cfg(not(target_os = "macos"))]
let ret = lstat(path, stat_ptr);
debug!("ret: {}", ret);
if ret != 0 {
return ret;
}
utils::copy_stat_into_wasm(ctx, buf_ptr, &stat);
}
0
}
/// fallocate
pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall324 (fallocate) {}", _which);
let _fd: c_int = varargs.get(ctx);
let _mode: c_int = varargs.get(ctx);
let _offset: off_t = varargs.get(ctx);
let _len: off_t = varargs.get(ctx);
#[cfg(not(target_os = "macos"))]
unsafe {
fallocate(_fd, _mode, _offset, _len)
}
#[cfg(target_os = "macos")]
{
unimplemented!()
}
}

View File

@ -1,22 +1,23 @@
use crate::utils::copy_cstr_into_wasm; use crate::utils::copy_cstr_into_wasm;
use crate::utils::read_string_from_wasm;
use crate::varargs::VarArgs; use crate::varargs::VarArgs;
use libc::mkdir; use libc::mkdir;
use libc::open; use libc::open;
use rand::Rng; use rand::Rng;
use std::env; use std::env;
use std::ffi::CStr;
use std::ffi::CString; use std::ffi::CString;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::os::raw::c_int; use std::os::raw::c_int;
use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::vm::Ctx;
#[allow(non_camel_case_types)]
type pid_t = c_int; type pid_t = c_int;
/// open /// open
pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall5 (open) {}", which); debug!("emscripten::___syscall5 (open) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let flags: i32 = varargs.get(ctx); let flags: i32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx);
@ -34,15 +35,15 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
let mut urandom_file = File::create(tmp_dir).unwrap(); let mut urandom_file = File::create(tmp_dir).unwrap();
// create some random bytes and put them into the file // create some random bytes and put them into the file
let random_bytes = rand::thread_rng().gen::<[u8; 32]>(); let random_bytes = rand::thread_rng().gen::<[u8; 32]>();
urandom_file.write_all(&random_bytes); let _ = urandom_file.write_all(&random_bytes).unwrap();
// put the file path string into wasm memory // put the file path string into wasm memory
let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) }; let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) };
let raw_pointer_to_urandom_file = let raw_pointer_to_urandom_file =
emscripten_memory_pointer!(ctx.memory(0), urandom_file_offset) as *const i8; emscripten_memory_pointer!(ctx.memory(0), urandom_file_offset) as *const i8;
let fd = unsafe { open(raw_pointer_to_urandom_file, flags, mode) }; let fd = unsafe { open(raw_pointer_to_urandom_file, flags, mode) };
debug!( debug!(
"=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}", "=> pathname: {}, flags: {}, mode: {} = fd: {}",
pathname, flags, mode, fd, s pathname, flags, mode, fd
); );
fd fd
} }
@ -57,21 +58,78 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
} }
} }
/// link
pub fn ___syscall9(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall9 (link) {}", _which);
unimplemented!()
}
/// ftruncate64
pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall194 - stub");
unimplemented!()
}
// chown // chown
pub fn ___syscall212(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall212(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", which); debug!("emscripten::___syscall212 (chown) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// access
pub fn ___syscall33(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall33 (access) {}", _which);
unimplemented!()
}
/// nice
pub fn ___syscall34(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall34 (nice) {}", _which);
unimplemented!()
}
// mkdir // mkdir
pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", which); debug!("emscripten::___syscall39 (mkdir) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
let pathname: u32 = varargs.get(ctx); let pathname: u32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx);
let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8;
unsafe { mkdir(pathname_addr) } unsafe { mkdir(pathname_addr) }
} }
/// dup
pub fn ___syscall41(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall41 (dup) {}", _which);
unimplemented!()
}
/// getrusage
pub fn ___syscall77(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall77 (getrusage) {}", _which);
unimplemented!()
}
/// symlink
pub fn ___syscall83(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall83 (symlink) {}", _which);
unimplemented!()
}
/// lchown
pub fn ___syscall198(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall198 (lchown) {}", _which);
unimplemented!()
}
/// getgid
pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall200 (getgid)");
unimplemented!()
}
// getgid // getgid
pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall201 (getgid)"); debug!("emscripten::___syscall201 (getgid)");
@ -85,60 +143,122 @@ pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1 -1
} }
/// getgroups
pub fn ___syscall205(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall205 (getgroups) {}", _which);
unimplemented!()
}
/// madvise
pub fn ___syscall219(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall212 (chown) {}", _which);
unimplemented!()
}
/// dup3 /// dup3
pub fn ___syscall330(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { pub fn ___syscall330(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall330 (dup3)"); debug!("emscripten::___syscall330 (dup3)");
-1 -1
} }
/// ioctl /// ioctl
pub fn ___syscall54(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall54(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall54 (ioctl) {}", which); debug!("emscripten::___syscall54 (ioctl) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// fchmod
pub fn ___syscall94(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fchmod) {}", _which);
unimplemented!()
}
// socketcall // socketcall
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall102(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall102(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall102 (socketcall) {}", which); debug!("emscripten::___syscall102 (socketcall) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// fsync
pub fn ___syscall118(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall118 (fsync) {}", _which);
unimplemented!()
}
// pread // pread
pub fn ___syscall180(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall180(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall180 (pread) {}", which); debug!("emscripten::___syscall180 (pread) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
// pwrite // pwrite
pub fn ___syscall181(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall181(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall181 (pwrite) {}", which); debug!("emscripten::___syscall181 (pwrite) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// wait4 /// wait4
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall114(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> pid_t { pub fn ___syscall114(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> pid_t {
debug!("emscripten::___syscall114 (wait4)"); debug!("emscripten::___syscall114 (wait4)");
-1 -1
} }
// select // select
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub fn ___syscall142(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall142(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall142 (newselect) {}", which); debug!("emscripten::___syscall142 (newselect) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// fdatasync
pub fn ___syscall148(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall148 (fdatasync) {}", _which);
unimplemented!();
}
// setpgid // setpgid
pub fn ___syscall57(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall57(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall57 (setpgid) {}", which); debug!("emscripten::___syscall57 (setpgid) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// uname /// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten. // NOTE: Wondering if we should return custom utsname, like Emscripten.
pub fn ___syscall122(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall122(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall122 (uname) {}", which); debug!("emscripten::___syscall122 (uname) {}", which);
#[cfg(not(feature = "debug"))]
let _ = which;
-1 -1
} }
/// lstat64
pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall196 (lstat64) - stub");
-1
}
/// fchown
pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall207 (fchown) {}", _which);
unimplemented!()
}
/// fallocate
pub fn ___syscall324(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall324 (fallocate) {}", _which);
unimplemented!()
}

View File

@ -10,6 +10,7 @@ use libc::{clockid_t, time as libc_time};
use libc::time_t; use libc::time_t;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
#[allow(non_camel_case_types)]
type clockid_t = c_int; type clockid_t = c_int;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -75,8 +76,10 @@ pub fn _clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
tv_nsec: i32, tv_nsec: i32,
} }
#[allow(unreachable_patterns)]
let timespec = match clk_id { let timespec = match clk_id {
CLOCK_REALTIME => time::get_time(), CLOCK_REALTIME => time::get_time(),
CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE => { CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE => {
let precise_ns = time::precise_time_ns(); let precise_ns = time::precise_time_ns();
time::Timespec::new( time::Timespec::new(
@ -295,7 +298,7 @@ pub fn _time(ctx: &mut Ctx, time_p: u32) -> i32 {
/// emscripten: _strftime /// emscripten: _strftime
pub fn _strftime( pub fn _strftime(
_ctx: &mut Ctx, ctx: &mut Ctx,
s_ptr: c_int, s_ptr: c_int,
maxsize: u32, maxsize: u32,
format_ptr: c_int, format_ptr: c_int,
@ -305,5 +308,67 @@ pub fn _strftime(
"emscripten::_strftime {} {} {} {}", "emscripten::_strftime {} {} {} {}",
s_ptr, maxsize, format_ptr, tm_ptr s_ptr, maxsize, format_ptr, tm_ptr
); );
0
#[allow(clippy::cast_ptr_alignment)]
let s = emscripten_memory_pointer!(ctx.memory(0), s_ptr) as *mut c_char;
#[allow(clippy::cast_ptr_alignment)]
let format = emscripten_memory_pointer!(ctx.memory(0), format_ptr) as *const c_char;
#[allow(clippy::cast_ptr_alignment)]
let tm = emscripten_memory_pointer!(ctx.memory(0), tm_ptr) as *const guest_tm;
let format_string = unsafe { std::ffi::CStr::from_ptr(format).to_str().unwrap() };
debug!("=> format_string: {:?}", format_string);
let tm = unsafe { &*tm };
let rust_tm = ::time::Tm {
tm_sec: tm.tm_sec,
tm_min: tm.tm_min,
tm_hour: tm.tm_hour,
tm_mday: tm.tm_mday,
tm_mon: tm.tm_mon,
tm_year: tm.tm_year,
tm_wday: tm.tm_wday,
tm_yday: tm.tm_yday,
tm_isdst: tm.tm_isdst,
tm_utcoff: tm.tm_gmtoff,
tm_nsec: 0,
};
let result_str = match ::time::strftime(format_string, &rust_tm) {
Ok(res_string) => res_string,
// TODO: maybe match on e in Err(e) and return different values if required
_ => return 0,
};
// pad for null?
let bytes = result_str.chars().count();
if bytes as u32 > maxsize {
return 0;
} else {
// write output string
for (i, c) in result_str.chars().enumerate() {
unsafe { *s.add(i) = c as c_char };
}
// null terminate?
bytes as i32
}
}
/// emscripten: _strftime_l
pub fn _strftime_l(
ctx: &mut Ctx,
s_ptr: c_int,
maxsize: u32,
format_ptr: c_int,
tm_ptr: c_int,
_last: c_int,
) -> i32 {
debug!(
"emscripten::_strftime_l {} {} {} {}",
s_ptr, maxsize, format_ptr, tm_ptr
);
_strftime(ctx, s_ptr, maxsize, format_ptr, tm_ptr)
} }

View File

@ -90,8 +90,9 @@ pub unsafe fn allocate_cstr_on_stack<'a>(ctx: &'a mut Ctx, s: &str) -> (u32, &'a
(offset, slice) (offset, slice)
} }
#[cfg(not(target_os = "windows"))]
pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 { pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 {
let total_num = { let _total_num = {
let mut ptr = cstrs; let mut ptr = cstrs;
let mut counter = 0; let mut counter = 0;
while !(*ptr).is_null() { while !(*ptr).is_null() {
@ -102,7 +103,7 @@ pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_
}; };
debug!( debug!(
"emscripten::copy_terminated_array_of_cstrs::total_num: {}", "emscripten::copy_terminated_array_of_cstrs::total_num: {}",
total_num _total_num
); );
0 0
} }
@ -124,7 +125,7 @@ pub struct GuestStat {
st_atime: u64, st_atime: u64,
st_mtime: u64, st_mtime: u64,
st_ctime: u64, st_ctime: u64,
st_ino: u64, st_ino: u32,
} }
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
@ -155,6 +156,7 @@ pub unsafe fn copy_stat_into_wasm(ctx: &mut Ctx, buf: u32, stat: &stat) {
(*stat_ptr).st_ino = stat.st_ino as _; (*stat_ptr).st_ino = stat.st_ino as _;
} }
#[allow(dead_code)] // it's used in `env/windows/mod.rs`.
pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String { pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String {
let v: Vec<u8> = memory.view()[(offset as usize)..] let v: Vec<u8> = memory.view()[(offset as usize)..]
.iter() .iter()
@ -169,15 +171,40 @@ mod tests {
use super::is_emscripten_module; use super::is_emscripten_module;
use std::sync::Arc; use std::sync::Arc;
use wabt::wat2wasm; use wabt::wat2wasm;
use wasmer_clif_backend::CraneliftCompiler; use wasmer_runtime_core::backend::Compiler;
use wasmer_runtime_core::compile_with; use wasmer_runtime_core::compile_with;
#[cfg(feature = "clif")]
fn get_compiler() -> impl Compiler {
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
#[cfg(feature = "llvm")]
fn get_compiler() -> impl Compiler {
use wasmer_llvm_backend::LLVMCompiler;
LLVMCompiler::new()
}
#[cfg(feature = "singlepass")]
fn get_compiler() -> impl Compiler {
use wasmer_singlepass_backend::SinglePassCompiler;
SinglePassCompiler::new()
}
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
fn get_compiler() -> impl Compiler {
panic!("compiler not specified, activate a compiler via features");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
#[test] #[test]
fn should_detect_emscripten_files() { fn should_detect_emscripten_files() {
const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_true.wast"); const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_true.wast");
let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm"); let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm");
let module = compile_with(&wasm_binary[..], &CraneliftCompiler::new()) let module =
.expect("WASM can't be compiled"); compile_with(&wasm_binary[..], &get_compiler()).expect("WASM can't be compiled");
let module = Arc::new(module); let module = Arc::new(module);
assert!(is_emscripten_module(&module)); assert!(is_emscripten_module(&module));
} }
@ -186,8 +213,8 @@ mod tests {
fn should_detect_non_emscripten_files() { fn should_detect_non_emscripten_files() {
const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_false.wast"); const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_false.wast");
let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm"); let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm");
let module = compile_with(&wasm_binary[..], &CraneliftCompiler::new()) let module =
.expect("WASM can't be compiled"); compile_with(&wasm_binary[..], &get_compiler()).expect("WASM can't be compiled");
let module = Arc::new(module); let module = Arc::new(module);
assert!(!is_emscripten_module(&module)); assert!(!is_emscripten_module(&module));
} }

Some files were not shown because too many files have changed in this diff Show More