Merge branch 'master' into feature/metering-c-api

This commit is contained in:
Ivan Enderlin
2021-03-01 16:43:16 +01:00
62 changed files with 2690 additions and 1116 deletions

View File

@@ -1,4 +1,13 @@
[target.'cfg(target_os = "linux")']
rustflags = [
"-C", "link-arg=-Wl,-E"
# Put the VM functions in the dynamic symbol table.
"-C", "link-arg=-Wl,-E",
]
[target.'cfg(target_os = "windows")']
rustflags = [
# Enable `libwasmer` to be statically linked against the C Runtime
# Libraries (CRT) to reduce the number of dependencies inside the
# DLL.
"-C", "target-feature=+crt-static",
]

15
.github/workflows/cargo-deny.yaml vendored Normal file
View File

@@ -0,0 +1,15 @@
on:
push:
branches:
- '**'
- '!master'
name: cargo-deny
jobs:
deny-check:
name: cargo-deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: EmbarkStudios/cargo-deny-action@v1

View File

@@ -18,7 +18,7 @@ jobs:
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.48.0
toolchain: 1.49
override: true
- name: Install LLVM
shell: bash

View File

@@ -19,7 +19,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: 1.48.0
toolchain: 1.49
override: true
components: rustfmt, clippy
- run: make lint

View File

@@ -42,14 +42,14 @@ jobs:
include:
- build: linux-x64
os: ubuntu-18.04
rust: 1.48
rust: 1.49
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz'
artifact_name: 'wasmer-linux-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_linux'
run_integration_tests: true
- build: macos-x64
os: macos-latest
rust: 1.48
rust: 1.49
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/darwin-amd64.tar.gz'
artifact_name: 'wasmer-darwin-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_mac'
@@ -61,7 +61,7 @@ jobs:
artifact_name: 'wasmer-darwin-arm64'
- build: windows-x64
os: windows-latest
rust: 1.48
rust: 1.49
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/windows-amd64.tar.gz'
artifact_name: 'wasmer-windows-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_win'
@@ -69,7 +69,7 @@ jobs:
- build: linux-aarch64
os: [self-hosted, linux, ARM64]
random_sccache_port: true
rust: 1.48
rust: 1.49
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-aarch64.tar.gz'
artifact_name: 'wasmer-linux-aarch64'
run_integration_tests: false
@@ -105,12 +105,13 @@ jobs:
shell: bash
run: |
curl --proto '=https' --tlsv1.2 -sSf ${{ matrix.llvm_url }} -L -o llvm.tar.gz
mkdir ${{ env.LLVM_DIR }}
tar xf llvm.tar.gz --strip-components=1 -C ${{ env.LLVM_DIR }}
echo "${{ env.LLVM_DIR }}/bin" >> $GITHUB_PATH
echo "LLVM_SYS_110_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV
LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }}
mkdir ${LLVM_DIR}
tar xf llvm.tar.gz --strip-components=1 -C ${LLVM_DIR}
echo "${LLVM_DIR}/bin" >> $GITHUB_PATH
echo "LLVM_SYS_110_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
env:
LLVM_DIR: ${{ github.workspace }}/llvm-11
LLVM_DIR: .llvm
- name: Set up dependencies for Mac OS
run: |
brew install automake
@@ -131,8 +132,8 @@ jobs:
key: ${{ matrix.build }}-${{ matrix.target }}-sccache-bin-${{ env.CARGO_SCCACHE_VERSION }}-v1
- name: Install sccache
run: |
if [ ! -f ${{ runner.tool_cache }}/cargo-sccache/bin/sccache ]; then
cargo install sccache --git https://github.com/paritytech/sccache.git --no-default-features --features=dist-client,azure --root ${{ runner.tool_cache }}/cargo-sccache
if [ ! -f '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' ]; then
cargo install sccache --git https://github.com/paritytech/sccache.git --no-default-features --features=dist-client,azure --root '${{ runner.tool_cache }}/cargo-sccache'
fi
shell: bash
- name: Setup Rust target
@@ -164,10 +165,11 @@ jobs:
shell: bash
- name: Start sccache
run: |
chmod +x ${{ runner.tool_cache }}/cargo-sccache/bin/sccache
${{ runner.tool_cache }}/cargo-sccache/bin/sccache --start-server
${{ runner.tool_cache }}/cargo-sccache/bin/sccache -s
echo "RUSTC_WRAPPER=${{ runner.tool_cache }}/cargo-sccache/bin/sccache" >> $GITHUB_ENV
chmod +x '${{ runner.tool_cache }}/cargo-sccache/bin/sccache'
'${{ runner.tool_cache }}/cargo-sccache/bin/sccache' --start-server
'${{ runner.tool_cache }}/cargo-sccache/bin/sccache' -s
echo 'RUSTC_WRAPPER=${{ runner.tool_cache }}/cargo-sccache/bin/sccache' >> $GITHUB_ENV
shell: bash
- name: Test
run: |
make test
@@ -346,6 +348,7 @@ jobs:
uses: actions/download-artifact@v2
with:
path: artifacts
- name: Create Release
id: create_release
uses: actions/create-release@v1
@@ -356,18 +359,28 @@ jobs:
release_name: Release ${{ needs.setup.outputs.VERSION }}
draft: true
prerelease: false
- name: Upload Release Asset Windows
id: upload-release-asset-windows
- name: Upload Release Asset Windows Installer
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: artifacts/wasmer-windows-amd64/WasmerInstaller.exe
asset_name: wasmer-windows.exe
asset_content_type: application/vnd.microsoft.portable-executable
- name: Upload Release Asset Windows
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: artifacts/wasmer-windows-amd64/wasmer.tar.gz
asset_name: wasmer-windows-amd64.tar.gz
asset_content_type: application/gzip
- name: Upload Release Asset Linux amd64
id: upload-release-asset-linux-amd64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -376,8 +389,8 @@ jobs:
asset_path: artifacts/wasmer-linux-amd64/wasmer.tar.gz
asset_name: wasmer-linux-amd64.tar.gz
asset_content_type: application/gzip
- name: Upload Release Asset Mac amd64
id: upload-release-asset-mac-amd64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -386,8 +399,8 @@ jobs:
asset_path: artifacts/wasmer-darwin-amd64/wasmer.tar.gz
asset_name: wasmer-darwin-amd64.tar.gz
asset_content_type: application/gzip
- name: Upload Release Asset Mac arm64
id: upload-release-asset-mac-arm64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -396,8 +409,8 @@ jobs:
asset_path: artifacts/wasmer-darwin-arm64/wasmer.tar.gz
asset_name: wasmer-darwin-arm64.tar.gz
asset_content_type: application/gzip
- name: Upload Release Asset Linux aarch64
id: upload-release-asset-linux-aarch64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -419,7 +432,7 @@ jobs:
path: ${{ runner.tool_cache }}/cargo-audit
key: cargo-audit-bin-${{ env.CARGO_AUDIT_VERSION }}
- run: |
echo "${{ runner.tool_cache }}/cargo-audit/bin" >> $GITHUB_PATH
echo "'${{ runner.tool_cache }}/cargo-audit/bin'" >> $GITHUB_PATH
- run: |
cargo install cargo-audit --version ${{ env.CARGO_AUDIT_VERSION }} --root ${{ runner.tool_cache }}/cargo-audit
cargo install cargo-audit --version ${{ env.CARGO_AUDIT_VERSION }} --root '${{ runner.tool_cache }}/cargo-audit'
cargo audit

View File

@@ -8,10 +8,17 @@
## **[Unreleased]**
### Added
- [#2123](https://github.com/wasmerio/wasmer/pull/2123) Use `ENABLE_{{compiler_name}}=(0|1)` to resp. force to disable or enable a compiler when running the `Makefile`, e.g. `ENABLE_LLVM=1 make build-wasmer`.
- [#2123](https://github.com/wasmerio/wasmer/pull/2123) `libwasmer` comes with all available compilers per target instead of Cranelift only.
- [#2118](https://github.com/wasmerio/wasmer/pull/2118) Add an unstable non-standard C API to query available engines and compilers.
### Changed
- [#2113](https://github.com/wasmerio/wasmer/pull/2113) Bump minimum supported Rust version to 1.49
- [#2144](https://github.com/wasmerio/wasmer/pull/2144) Bump cranelift version to 0.70
- [#2149](https://github.com/wasmerio/wasmer/pull/2144) `wasmer-engine-native` looks for clang-11 instead of clang-10.
### Fixed
- [#2117](https://github.com/wasmerio/wasmer/pull/2117) Formalize API prefixes in the C API. Only unstable functions have been renamed.
- [#2097](https://github.com/wasmerio/wasmer/pull/2097) Fix how string's length is computed in `wasm_cpu_features_add` in the C API.
- [#2101](https://github.com/wasmerio/wasmer/pull/2101) cflags emitted by `wasmer config --pkg-config` are now correct.

706
Cargo.lock generated

File diff suppressed because it is too large Load Diff

434
Makefile
View File

@@ -1,112 +1,329 @@
# uname only works in *Unix like systems
ifneq ($(OS), Windows_NT)
ARCH := $(shell uname -m)
UNAME_S := $(shell uname -s)
LIBC ?= $(shell ldd 2>&1 | grep -o musl | head -n1)
SHELL=/bin/bash
#####
#
# The Matrix
#
#####
# The matrix is the product of the following columns:
#
# |------------|--------|----------|--------------|-------|
# | Compiler Engine Platform Architecture libc |
# |------------|--------|----------|--------------|-------|
# | Cranelift | JIT | Linux | amd64 | glibc |
# | LLVM | Native | Darwin | aarch64 | musl |
# | Singlepass | | Windows | | |
# |------------|--------|----------|--------------|-------|
#
# Here is what works and what doesn't:
#
# * Cranelift with the JIT engine works everywhere,
#
# * Cranelift with the Native engine works on Linux+Darwin/`amd64`,
# but it doesn't work on */`aarch64` or Windows/*.
#
# * LLVM with the JIT engine works on Linux+Darwin/`amd64`,
# but it doesn't work on */`aarch64` or Windows/*.
#
# * LLVM with the Native engine works on
# Linux+Darwin/`amd64`+`aarch64`, but it doesn't work on Windows/*.
#
# * Singlepass with the JIT engine works on Linux+Darwin/`amd64`, but
# it doesn't work on */`aarch64` or Windows/*.
#
# * Singlepass with the Native engine doesn't work because it doesn't
# know how to output object files for the moment.
#
# * Windows isn't tested on `aarch64`, that's why we consider it's not
# working, but it might possibly be.
#####
#
# Define the “Platform” and “Architecture” columns of the matrix.
#
#####
IS_DARWIN := 0
IS_LINUX := 0
IS_WINDOWS := 0
IS_AMD64 := 0
IS_AARCH64 := 0
# Test Windows apart because it doesn't support `uname -s`.
ifeq ($(OS), Windows_NT)
# We can assume it will likely be in amd64.
IS_AMD64 := 1
IS_WINDOWS := 1
else
# We can assume, if in windows it will likely be in x86_64
ARCH := x86_64
UNAME_S :=
LIBC ?=
# Platform
uname := $(shell uname -s)
ifeq ($(uname), Darwin)
IS_DARWIN := 1
else ifeq ($(uname), Linux)
IS_LINUX := 1
else
# We use spaces instead of tabs to indent `$(error)`
# otherwise it's considered as a command outside a
# target and it will fail.
$(error Unrecognized platform, expect `Darwin`, `Linux` or `Windows_NT`)
endif
# Architecture
uname := $(shell uname -m)
ifeq ($(uname), x86_64)
IS_AMD64 := 1
else ifneq (, $(filter $(uname), aarch64 arm64))
IS_AARCH64 := 1
else
# We use spaces instead of tabs to indent `$(error)`
# otherwise it's considered as a command outside a
# target and it will fail.
$(error Unrecognized architecture, expect `x86_64`, `aarch64` or `arm64`)
endif
# Libc
LIBC ?= $(shell ldd 2>&1 | grep -o musl | head -n1)
endif
#####
#
# Define the “Compiler” column of the matrix.
#
#####
# Variables that can be overriden by the users to force to enable or
# to disable a specific compiler.
ENABLE_CRANELIFT ?=
ENABLE_LLVM ?=
ENABLE_SINGLEPASS ?=
# Which compilers we build. These have dependencies that may not be on the system.
compilers := cranelift
compilers :=
# In the form "$(compiler)-$(engine)" which compiler+engine combinations to test
# in `make test`.
test_compilers_engines :=
##
# Cranelift
##
# Autodetect LLVM from llvm-config
ifneq (, $(shell which llvm-config 2>/dev/null))
LLVM_VERSION := $(shell llvm-config --version)
# If findstring is not empty, then it have found the value
ifneq (, $(findstring 10,$(LLVM_VERSION)))
compilers += llvm
endif
ifneq (, $(findstring 11,$(LLVM_VERSION)))
compilers += llvm
endif
else
ifneq (, $(shell which llvm-config-10 2>/dev/null))
compilers += llvm
endif
ifneq (, $(shell which llvm-config-11 2>/dev/null))
# If the user didn't disable the Cranelift compiler…
ifneq ($(ENABLE_CRANELIFT), 0)
# … then it can always be enabled.
compilers += cranelift
ENABLE_CRANELIFT := 1
endif
##
# LLVM
##
# If the user didn't disable the LLVM compiler…
ifneq ($(ENABLE_LLVM), 0)
# … then maybe the user forced to enable the LLVM compiler.
ifeq ($(ENABLE_LLVM), 1)
compilers += llvm
# … otherwise, we try to autodetect LLVM from `llvm-config`
else ifneq (, $(shell which llvm-config 2>/dev/null))
LLVM_VERSION := $(shell llvm-config --version)
# If findstring is not empty, then it have found the value
ifneq (, $(findstring 11,$(LLVM_VERSION)))
compilers += llvm
else ifneq (, $(findstring 10,$(LLVM_VERSION)))
compilers += llvm
endif
# … or try to autodetect LLVM from `llvm-config-<version>`.
else
ifneq (, $(shell which llvm-config-11 2>/dev/null))
compilers += llvm
else ifneq (, $(shell which llvm-config-10 2>/dev/null))
compilers += llvm
endif
endif
endif
ifeq ($(ARCH), x86_64)
test_compilers_engines += cranelift-jit
# LLVM could be enabled if not in Windows
ifneq ($(OS), Windows_NT)
ifneq ($(LIBC), musl)
# Native engine doesn't work on Windows and musl yet.
test_compilers_engines += cranelift-native
endif
# Singlepass doesn't work yet on Windows.
compilers += singlepass
# Singlepass doesn't work with the native engine.
test_compilers_engines += singlepass-jit
ifneq (, $(findstring llvm,$(compilers)))
test_compilers_engines += llvm-jit
ifneq (, $(findstring llvm,$(compilers)))
ENABLE_LLVM := 1
endif
##
# Singlepass
##
# If the user didn't disable the Singlepass compiler…
ifneq ($(ENABLE_SINGLEPASS), 0)
# … then maybe the user forced to enable the Singlepass compiler.
ifeq ($(ENABLE_SINGLEPASS), 1)
compilers += singlepass
# … otherwise, we try to check whether Singlepass works on this host.
else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
ifeq ($(IS_AMD64), 1)
compilers += singlepass
endif
endif
endif
ifneq (, $(findstring singlepass,$(compilers)))
ENABLE_SINGLEPASS := 1
endif
##
# Clean the `compilers` variable.
##
compilers := $(strip $(compilers))
#####
#
# Define the “Engine” column of the matrix.
#
#####
# The engine is part of a pair of kind (compiler, engine). All the
# pairs are stored in the `compilers_engines` variable.
compilers_engines :=
##
# The Cranelift case.
##
ifeq ($(ENABLE_CRANELIFT), 1)
compilers_engines += cranelift-jit
ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
ifeq ($(IS_AMD64), 1)
ifneq ($(LIBC), musl)
# Native engine doesn't work on musl yet.
test_compilers_engines += llvm-native
compilers_engines += cranelift-native
endif
endif
endif
endif
# If it's an aarch64/arm64 chip
# Using filter as a logical OR
# https://stackoverflow.com/questions/7656425/makefile-ifeq-logical-or
use_system_ffi =
ifneq (,$(filter $(ARCH),aarch64 arm64))
test_compilers_engines += cranelift-jit
ifneq (, $(findstring llvm,$(compilers)))
test_compilers_engines += llvm-native
endif
# if we are in macos arm64, we use the system libffi for the capi
ifeq ($(UNAME_S), Darwin)
use_system_ffi = yes
##
# The LLVM case.
##
ifeq ($(ENABLE_LLVM), 1)
ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
ifeq ($(IS_AMD64), 1)
compilers_engines += llvm-jit
compilers_engines += llvm-native
else ifeq ($(IS_AARCH64), 1)
compilers_engines += llvm-native
endif
endif
endif
# if the user has set the `WASMER_CAPI_USE_SYSTEM_LIBFFI` var to 1 also
# use the system libffi.
##
# The Singlepass case.
##
ifeq ($(ENABLE_SINGLEPASS), 1)
ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
ifeq ($(IS_AMD64), 1)
compilers_engines += singlepass-jit
endif
endif
endif
# Clean the `compilers_engines` variable.
compilers_engines := $(strip $(compilers_engines))
#####
#
# Miscellaneous.
#
#####
# The `libffi` library doesn't support Darwin/aarch64. In this
# particular case, we need to use the `libffi` version provided by the
# system itself.
#
# See <https://github.com/libffi/libffi/pull/621>.
use_system_ffi := 0
ifeq ($(IS_DARWIN), 1)
ifeq ($(IS_AARCH64), 1)
use_system_ffi = 1
endif
endif
# If the user has set the `WASMER_CAPI_USE_SYSTEM_LIBFFI` environment
# variable to 1, then also use the system `libffi`.
ifeq ($(WASMER_CAPI_USE_SYSTEM_LIBFFI), 1)
use_system_ffi = yes
use_system_ffi = 1
endif
ifdef use_system_ffi
#####
#
# Cargo features.
#
#####
# Define the default Cargo features for the `wasmer-c-api` crate.
ifeq ($(use_system_ffi), 1)
capi_default_features := --features system-libffi
endif
compilers := $(filter-out ,$(compilers))
test_compilers_engines := $(filter-out ,$(test_compilers_engines))
# Small trick to define a space and a comma.
space := $() $()
comma := ,
ifneq ($(OS), Windows_NT)
# Define the compiler Cargo features for all crates.
compiler_features := --features $(subst $(space),$(comma),$(compilers))
# Define the compiler Cargo features for the C API. It always excludes
# LLVM for the moment.
capi_compiler_features := --features $(subst $(space),$(comma),$(filter-out llvm, $(compilers)))
#####
#
# Display information.
#
#####
ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
bold := $(shell tput bold 2>/dev/null || echo -n '')
green := $(shell tput setaf 2 2>/dev/null || echo -n '')
reset := $(shell tput sgr0 2>/dev/null || echo -n '')
endif
compiler_features_spaced := $(foreach compiler,$(compilers),$(compiler))
compiler_features := --features "$(compiler_features_spaced)"
HOST_TARGET=$(shell rustup show | grep 'Default host: ' | cut -d':' -f2 | tr -d ' ')
$(info -----------)
$(info $(bold)$(green)INFORMATION$(reset))
$(info -----------)
$(info )
$(info Host Target: `$(bold)$(green)$(HOST_TARGET)$(reset)`.)
ifneq (, $(LIBC))
$(info C standard library: $(bold)$(green)$(LIBC)$(reset))
# We use spaces instead of tabs to indent `$(info)`
# otherwise it's considered as a command outside a
# target and it will fail.
$(info C standard library: $(bold)$(green)$(LIBC)$(reset))
endif
$(info Host target: $(bold)$(green)$(HOST_TARGET)$(reset))
$(info Available compilers: $(bold)$(green)${compilers}$(reset))
$(info Compilers features: $(bold)$(green)${compiler_features}$(reset))
$(info Available compilers + engines for test: $(bold)$(green)${test_compilers_engines}$(reset))
$(info Enabled Compilers: $(bold)$(green)$(subst $(space),$(reset)$(comma)$(space)$(bold)$(green),$(compilers))$(reset).)
$(info Compilers + engines pairs (for testing): $(bold)$(green)${compilers_engines}$(reset))
$(info Cargo features:)
$(info   - Compilers for all crates: `$(bold)$(green)${compiler_features}$(reset)`.)
$(info   - Compilers for the C API: `$(bold)$(green)${capi_compiler_features}$(reset)`.)
$(info   - Default for the C API: `$(bold)$(green)${capi_default_features}$(reset)`.)
$(info )
$(info )
$(info --------------)
$(info $(bold)$(green)RULE EXECUTION$(reset))
$(info --------------)
$(info )
$(info )
############
@@ -136,10 +353,10 @@ build-wasmer-debug:
# rpath = false
build-wasmer-headless-minimal:
RUSTFLAGS="-C panic=abort" xargo build --target $(HOST_TARGET) --release --manifest-path=lib/cli/Cargo.toml --no-default-features --features headless-minimal --bin wasmer-headless
ifeq ($(UNAME_S), Darwin)
ifeq ($(IS_DARWIN), 1)
strip -u target/$(HOST_TARGET)/release/wasmer-headless
else
ifeq ($(OS), Windows_NT)
ifeq ($(IS_WINDOWS), 1)
strip --strip-unneeded target/$(HOST_TARGET)/release/wasmer-headless.exe
else
strip --strip-unneeded target/$(HOST_TARGET)/release/wasmer-headless
@@ -151,7 +368,7 @@ get-wapm:
[ -d "wapm-cli" ] || git clone --branch $(WAPM_VERSION) https://github.com/wasmerio/wapm-cli.git
build-wapm: get-wapm
ifeq ($(UNAME_S), Darwin)
ifeq ($(IS_DARWIN), 1)
# We build it without bundling sqlite, as is included by default in macos
cargo build --release --manifest-path wapm-cli/Cargo.toml --no-default-features --features "packagesigning telemetry update-notifications"
else
@@ -165,8 +382,9 @@ build-docs-capi:
cd lib/c-api/doc/deprecated/ && doxygen doxyfile
cargo doc --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,jit,object-file,native,cranelift,wasi $(capi_default_features)
# We use cranelift as the default backend for the capi for now
build-capi: build-capi-cranelift
build-capi:
cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,wasi $(capi_default_features) $(capi_compiler_features)
build-capi-singlepass:
cargo build --manifest-path lib/c-api/Cargo.toml --release \
@@ -262,11 +480,11 @@ test-llvm-native:
test-llvm-jit:
cargo test --release $(compiler_features) --features "test-llvm test-jit"
test-singlepass: $(foreach singlepass_engine,$(filter singlepass-%,$(test_compilers_engines)),test-$(singlepass_engine))
test-singlepass: $(foreach singlepass_engine,$(filter singlepass-%,$(compilers_engines)),test-$(singlepass_engine))
test-cranelift: $(foreach cranelift_engine,$(filter cranelift-%,$(test_compilers_engines)),test-$(cranelift_engine))
test-cranelift: $(foreach cranelift_engine,$(filter cranelift-%,$(compilers_engines)),test-$(cranelift_engine))
test-llvm: $(foreach llvm_engine,$(filter llvm-%,$(test_compilers_engines)),test-$(llvm_engine))
test-llvm: $(foreach llvm_engine,$(filter llvm-%,$(compilers_engines)),test-$(llvm_engine))
test-packages:
cargo test -p wasmer --release
@@ -283,9 +501,32 @@ test-packages:
cargo test -p wasmer-derive --release
# The test-capi rules depend on the build-capi rules to build the .a files to
# link the tests against. cargo test doesn't know that the tests will be running
test-capi: $(foreach compiler_engine,$(test_compilers_engines),test-capi-$(compiler_engine))
# We want to run all the tests for all available compilers. The C API
# and the tests rely on the fact that one and only one default
# compiler will be selected at compile-time. Therefore, if we want to
# test exhaustively for all available compilers, we need to build and
# to test the C API with a different compiler each time.
#
# That's exactly what `test-capi` does: it runs `build-capi-*` with
# one compiler, and then it runs `test-capi-*` for that compiler
# specifically.
#
# Why do we need to run `build-capi-*` exactly? One might think that
# `cargo test` would generate a static library (`.a`) to link the
# tests against, but no. `cargo test` has no idea that we need this
# static library, that's normal the library isn't generated. Hence the
# need to run `cargo build` prior to testing to get all the build
# artifacts.
#
# Finally, `test-capi` calls `test-capi-all` that runs the tests for
# the library built with `build-capi`, which is the one we will
# deliver to the users, i.e. the one that may include multiple
# compilers.
test-capi: $(foreach compiler_engine,$(compilers_engines),test-capi-$(compiler_engine)) test-capi-all
test-capi-all: build-capi
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,wasi $(capi_default_features) $(capi_compiler_features) -- --nocapture
test-capi-singlepass-jit: build-capi-singlepass-jit test-capi-tests
cargo test --manifest-path lib/c-api/Cargo.toml --release \
@@ -299,11 +540,11 @@ test-capi-cranelift-native: build-capi-cranelift-native test-capi-tests
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,native,cranelift,wasi $(capi_default_features) -- --nocapture
test-capi-llvm-jit:
test-capi-llvm-jit: build-capi-llvm-jit test-capi-tests
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,llvm,wasi $(capi_default_features) -- --nocapture
test-capi-llvm-native:
test-capi-llvm-native: build-capi-llvm-native test-capi-tests
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,native,llvm,wasi $(capi_default_features) -- --nocapture
@@ -333,7 +574,7 @@ test-integration:
package-wapm:
mkdir -p "package/bin"
ifneq ($(OS), Windows_NT)
ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
if [ -d "wapm-cli" ]; then \
cp wapm-cli/target/release/wapm package/bin/ ;\
echo "#!/bin/bash\nwapm execute \"\$$@\"" > package/bin/wax ;\
@@ -343,13 +584,13 @@ else
if [ -d "wapm-cli" ]; then \
cp wapm-cli/target/release/wapm package/bin/ ;\
fi
ifeq ($(UNAME_S), Darwin)
ifeq ($(IS_DARWIN), 1)
codesign -s - package/bin/wapm
endif
endif
package-minimal-headless-wasmer:
ifeq ($(OS), Windows_NT)
ifeq ($(IS_WINDOWS), 1)
if [ -f "target/$(HOST_TARGET)/release/wasmer-headless.exe" ]; then \
cp target/$(HOST_TARGET)/release/wasmer-headless.exe package/bin ;\
fi
@@ -361,11 +602,11 @@ endif
package-wasmer:
mkdir -p "package/bin"
ifeq ($(OS), Windows_NT)
ifeq ($(IS_WINDOWS), 1)
cp target/release/wasmer.exe package/bin/
else
cp target/release/wasmer package/bin/
ifeq ($(UNAME_S), Darwin)
ifeq ($(IS_DARWIN), 1)
codesign -s - package/bin/wasmer
endif
endif
@@ -377,11 +618,11 @@ package-capi:
cp lib/c-api/wasmer_wasm.h* package/include
cp lib/c-api/wasm.h* package/include
cp lib/c-api/README.md package/include/README.md
ifeq ($(OS), Windows_NT)
ifeq ($(IS_WINDOWS), 1)
cp target/release/wasmer_c_api.dll package/lib/wasmer.dll
cp target/release/wasmer_c_api.lib package/lib/wasmer.lib
else
ifeq ($(UNAME_S), Darwin)
ifeq ($(IS_DARWIN), 1)
# For some reason in macOS arm64 there are issues if we copy constantly in the install_name_tool util
rm -f package/lib/libwasmer.dylib
cp target/release/libwasmer_c_api.dylib package/lib/libwasmer.dylib
@@ -411,15 +652,12 @@ distribution: package
cp LICENSE package/LICENSE
cp ATTRIBUTIONS.md package/ATTRIBUTIONS
mkdir -p dist
ifeq ($(OS), Windows_NT)
ifeq ($(IS_WINDOWS), 1)
iscc scripts/windows-installer/wasmer.iss
cp scripts/windows-installer/WasmerInstaller.exe dist/
else
cp LICENSE package/LICENSE
cp ATTRIBUTIONS.md package/ATTRIBUTIONS
endif
tar -C package -zcvf wasmer.tar.gz bin lib include LICENSE ATTRIBUTIONS
mv wasmer.tar.gz dist/
endif
#################
# Miscellaneous #

214
deny.toml Normal file
View File

@@ -0,0 +1,214 @@
# This template contains all of the possible sections and their default values
# Note that all fields that take a lint level have these possible values:
# * deny - An error will be produced and the check will fail
# * warn - A warning will be produced, but the check will not fail
# * allow - No warning or error will be produced, though in some cases a note
# will be
# The values provided in this template are the default values that will be used
# when any section or field is not specified in your own configuration
# If 1 or more target triples (and optionally, target_features) are specified,
# only the specified targets will be checked when running `cargo deny check`.
# This means, if a particular package is only ever used as a target specific
# dependency, such as, for example, the `nix` crate only being used via the
# `target_family = "unix"` configuration, that only having windows targets in
# this list would mean the nix crate, as well as any of its exclusive
# dependencies not shared by any other crates, would be ignored, as the target
# list here is effectively saying which targets you are building for.
targets = [
# The triple can be any string, but only the target triples built in to
# rustc (as of 1.40) can be checked against actual config expressions
#{ triple = "x86_64-unknown-linux-musl" },
# You can also specify which target_features you promise are enabled for a
# particular target. target_features are currently not validated against
# the actual valid features supported by the target architecture.
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
]
# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[advisories]
# The path where the advisory database is cloned/fetched into
db-path = "~/.cargo/advisory-db"
# The url(s) of the advisory databases to use
db-urls = ["https://github.com/rustsec/advisory-db"]
# The lint level for security vulnerabilities
vulnerability = "deny"
# The lint level for unmaintained crates
unmaintained = "warn"
# The lint level for crates that have been yanked from their source registry
yanked = "deny"
# The lint level for crates with security notices. Note that as of
# 2019-12-17 there are no security notice advisories in
# https://github.com/rustsec/advisory-db
notice = "warn"
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
#"RUSTSEC-0000-0000",
]
# Threshold for security vulnerabilities, any vulnerability with a CVSS score
# lower than the range specified will be ignored. Note that ignored advisories
# will still output a note when they are encountered.
# * None - CVSS Score 0.0
# * Low - CVSS Score 0.1 - 3.9
# * Medium - CVSS Score 4.0 - 6.9
# * High - CVSS Score 7.0 - 8.9
# * Critical - CVSS Score 9.0 - 10.0
#severity-threshold =
# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# The lint level for crates which do not have a detectable license
unlicensed = "deny"
# List of explictly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.7 short identifier (+ optional exception)].
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
]
# List of explictly disallowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.7 short identifier (+ optional exception)].
deny = [
"AGPL-1.0",
"AGPL-3.0",
]
# Lint level for licenses considered copyleft
copyleft = "warn"
# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
# * both - The license will be approved if it is both OSI-approved *AND* FSF
# * either - The license will be approved if it is either OSI-approved *OR* FSF
# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF
# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved
# * neither - This predicate is ignored and the default lint level is used
allow-osi-fsf-free = "either"
# Lint level used when no other predicates are matched
# 1. License isn't in the allow or deny lists
# 2. License isn't copyleft
# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither"
default = "deny"
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
# Each entry is the crate and version constraint, and its specific allow
# list
#{ allow = ["Zlib"], name = "adler32", version = "*" },
]
# Some crates don't have (easily) machine readable licensing information,
# adding a clarification entry for it allows you to manually specify the
# licensing information
#[[licenses.clarify]]
# The name of the crate the clarification applies to
#name = "ring"
# The optional version constraint for the crate
#version = "*"
# The SPDX expression for the license requirements of the crate
#expression = "MIT AND ISC AND OpenSSL"
# One or more files in the crate's source used as the "source of truth" for
# the license expression. If the contents match, the clarification will be used
# when running the license check, otherwise the clarification will be ignored
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
#license-files = [
# Each entry is a crate relative path, and the (opaque) hash of its contents
#{ path = "LICENSE", hash = 0xbd0eed23 }
#]
[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries
ignore = false
# One or more private registries that you might publish crates to, if a crate
# is only published to private registries, and ignore is true, the crate will
# not have its license(s) checked
registries = [
#"https://sekretz.com/registry
]
# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "deny"
# Lint level for when a crate version requirement is `*`
wildcards = "allow"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# List of crates that are allowed. Use with care!
allow = [
#{ name = "ansi_term", version = "=0.11.0" },
]
# List of crates to deny
deny = [
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
#{ name = "ansi_term", version = "=0.11.0" },
#
# Wrapper crates can optionally be specified to allow the crate when it
# is a direct dependency of the otherwise banned crate
#{ name = "ansi_term", version = "=0.11.0", wrappers = [] },
]
# Certain crates/versions that will be skipped when doing duplicate detection.
skip = [
{ name = "cfg-if", version = "=0.1.10" },
{ name = "strsim", version = "=0.8.0" },
{ name = "semver", version = "=0.9.0" },
{ name = "semver-parser", version = "=0.7.0" },
{ name = "rustc_version", version = "=0.2.3" },
{ name = "gimli", version = "=0.22.0" },
{ name = "wasi", version = "=0.9.0" },
{ name = "redox_syscall", version = "=0.1.57" },
{ name = "itertools", version = "0.9.0" },
{ name = "getrandom", version = "0.1.16" },
{ name = "wast", version = "=24.0.0" },
]
# Similarly to `skip` allows you to skip certain crates during duplicate
# detection. Unlike skip, it also includes the entire tree of transitive
# dependencies starting at the specified crate, up to a certain depth, which is
# by default infinite
skip-tree = [
#{ name = "ansi_term", version = "=0.11.0", depth = 20 },
]
# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "deny"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "deny"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []
#[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
#github = [""]
# 1 or more gitlab.com organizations to allow git sources for
#gitlab = [""]
# 1 or more bitbucket.org organizations to allow git sources for
#bitbucket = [""]

View File

@@ -36,7 +36,7 @@ pub enum Extern {
}
impl Extern {
/// Return the undelying type of the inner `Extern`.
/// Return the underlying type of the inner `Extern`.
pub fn ty(&self) -> ExternType {
match self {
Self::Function(ft) => ExternType::Function(ft.ty().clone()),

View File

@@ -37,12 +37,9 @@ serde = { version = "1", optional = true, features = ["derive"] }
thiserror = "1"
typetag = { version = "0.1", optional = true }
paste = "1.0"
# for generating code in the same way thot the wasm-c-api does
# Commented out for now until we can find a solution to the exported function problem
# wasmer-wasm-c-api = { version = "1.0.2", path = "crates/wasm-c-api" }
[dev-dependencies]
inline-c = "0.1.4"
inline-c = "0.1.5"
[features]
default = [

View File

@@ -494,9 +494,34 @@ fn exclude_items_from_wasm_c_api(builder: Builder) -> Builder {
.exclude_item("wasm_triple_new_from_host")
.exclude_item("wasm_triple_t")
.exclude_item("wasmer_compiler_t")
.exclude_item("wasmer_cpu_features_add")
.exclude_item("wasmer_cpu_features_delete")
.exclude_item("wasmer_cpu_features_new")
.exclude_item("wasmer_cpu_features_t")
.exclude_item("wasmer_engine_t")
.exclude_item("wasmer_metering_get_remaining_points")
.exclude_item("wasmer_metering_set_remaining_points")
.exclude_item("wasmer_is_compiler_available")
.exclude_item("wasmer_is_engine_available")
.exclude_item("wasmer_is_headless")
.exclude_item("wasmer_module_name")
.exclude_item("wasmer_module_set_name")
.exclude_item("wasmer_named_extern_module")
.exclude_item("wasmer_named_extern_name")
.exclude_item("wasmer_named_extern_t")
.exclude_item("wasmer_named_extern_unwrap")
.exclude_item("wasmer_named_extern_vec_copy")
.exclude_item("wasmer_named_extern_vec_delete")
.exclude_item("wasmer_named_extern_vec_new")
.exclude_item("wasmer_named_extern_vec_new_empty")
.exclude_item("wasmer_named_extern_vec_new_uninitialized")
.exclude_item("wasmer_target_delete")
.exclude_item("wasmer_target_new")
.exclude_item("wasmer_target_t")
.exclude_item("wasmer_triple_delete")
.exclude_item("wasmer_triple_new")
.exclude_item("wasmer_triple_new_from_host")
.exclude_item("wasmer_triple_t")
.exclude_item("wat2wasm")
}
@@ -528,6 +553,7 @@ fn build_inline_c_env_vars() {
let target = env::var("TARGET").unwrap();
assert_eq!(shared_object_dir.file_name(), Some(OsStr::new(&target)));
}
shared_object_dir.push(env::var("PROFILE").unwrap());
let shared_object_dir = shared_object_dir.as_path().to_string_lossy();
@@ -538,8 +564,11 @@ fn build_inline_c_env_vars() {
// * `-I`, add `include_dir` to include search path,
// * `-L`, add `shared_object_dir` to library search path,
// * `-D_DEBUG`, enable debug mode to enable `assert.h`.
// * `-D_CRT_SECURE_NO_WARNINGS`, disable security features in the
// Windows C runtime, which allows to use `getenv` without any
// warnings.
println!(
"cargo:rustc-env=INLINE_C_RS_CFLAGS=-I{I} -L{L} -D_DEBUG",
"cargo:rustc-env=INLINE_C_RS_CFLAGS=-I{I} -L{L} -D_DEBUG -D_CRT_SECURE_NO_WARNINGS",
I = include_dir,
L = shared_object_dir.clone(),
);

View File

@@ -1,5 +1,7 @@
pub use super::unstable::engine::wasm_config_set_target;
use super::unstable::target_lexicon::wasm_target_t;
pub use super::unstable::engine::{
wasm_config_set_target, wasmer_is_compiler_available, wasmer_is_engine_available,
};
use super::unstable::target_lexicon::wasmer_target_t;
use crate::error::{update_last_error, CApiError};
use cfg_if::cfg_if;
use std::sync::Arc;
@@ -114,6 +116,7 @@ pub struct wasm_config_t {
pub(super) target: Option<Box<wasm_target_t>>,
#[cfg(feature = "middlewares")]
pub(super) middlewares: Vec<wasmer_module_middleware_t>,
pub(super) target: Option<Box<wasmer_target_t>>,
}
/// Create a new default Wasmer configuration.
@@ -188,7 +191,7 @@ pub extern "C" fn wasm_config_delete(_config: Option<Box<wasm_config_t>>) {}
///
/// # Example
///
/// ```rust,no_run
/// ```rust
/// # use inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
@@ -198,8 +201,19 @@ pub extern "C" fn wasm_config_delete(_config: Option<Box<wasm_config_t>>) {}
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Use the Cranelift compiler.
/// wasm_config_set_compiler(config, CRANELIFT);
/// // Use the Cranelift compiler, if available.
/// if (wasmer_is_compiler_available(CRANELIFT)) {
/// wasm_config_set_compiler(config, CRANELIFT);
/// }
/// // Or maybe LLVM?
/// else if (wasmer_is_compiler_available(LLVM)) {
/// wasm_config_set_compiler(config, LLVM);
/// }
/// // Or maybe Singlepass?
/// else if (wasmer_is_compiler_available(SINGLEPASS)) {
/// wasm_config_set_compiler(config, SINGLEPASS);
/// }
/// // OK, let's run with no particular compiler.
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
@@ -231,7 +245,7 @@ pub extern "C" fn wasm_config_set_compiler(
///
/// # Example
///
/// ```rust,no_run
/// ```rust
/// # use inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
@@ -241,8 +255,15 @@ pub extern "C" fn wasm_config_set_compiler(
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Use the JIT engine.
/// wasm_config_set_engine(config, JIT);
/// // Use the JIT engine, if available.
/// if (wasmer_is_engine_available(JIT)) {
/// wasm_config_set_engine(config, JIT);
/// }
/// // Or maybe the Native engine?
/// else if (wasmer_is_engine_available(NATIVE)) {
/// wasm_config_set_engine(config, NATIVE);
/// }
/// // OK, let's do not specify any particular engine.
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);

View File

@@ -2,8 +2,12 @@
#[macro_export]
macro_rules! wasm_declare_vec_inner {
($name:ident) => {
wasm_declare_vec_inner!($name, wasm);
};
($name:ident, $prefix:ident) => {
paste::paste! {
#[doc = "Creates an empty vector of [`wasm_" $name "_t`].
#[doc = "Creates an empty vector of [`" $prefix "_" $name "_t`].
# Example
@@ -14,24 +18,24 @@ macro_rules! wasm_declare_vec_inner {
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Creates an empty vector of `wasm_" $name "_t`.
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new_empty(&vector);
// Creates an empty vector of `" $prefix "_" $name "_t`.
" $prefix "_" $name "_vec_t vector;
" $prefix "_" $name "_vec_new_empty(&vector);
// Check that it is empty.
assert(vector.size == 0);
// Free it.
wasm_" $name "_vec_delete(&vector);
" $prefix "_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new_empty>](out: *mut [<wasm_ $name _vec_t>]) {
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_empty>](out: *mut [<$prefix _ $name _vec_t>]) {
// TODO: actually implement this
[<wasm_ $name _vec_new_uninitialized>](out, 0);
[<$prefix _ $name _vec_new_uninitialized>](out, 0);
}
}
}
@@ -41,10 +45,14 @@ int main() {
#[macro_export]
macro_rules! wasm_declare_vec {
($name:ident) => {
paste::paste! {
#[doc = "Represents a vector of `wasm_" $name "_t`.
wasm_declare_vec!($name, wasm);
};
Read the documentation of [`wasm_" $name "_t`] to see more concrete examples.
($name:ident, $prefix:ident) => {
paste::paste! {
#[doc = "Represents a vector of `" $prefix "_" $name "_t`.
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples.
# Example
@@ -55,19 +63,19 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples.
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Create a vector of 2 `wasm_" $name "_t`.
wasm_" $name "_t x;
wasm_" $name "_t y;
wasm_" $name "_t* items[2] = {&x, &y};
// Create a vector of 2 `" $prefix "_" $name "_t`.
" $prefix "_" $name "_t x;
" $prefix "_" $name "_t y;
" $prefix "_" $name "_t* items[2] = {&x, &y};
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new(&vector, 2, (wasm_" $name "_t*) items);
" $prefix "_" $name "_vec_t vector;
" $prefix "_" $name "_vec_new(&vector, 2, (" $prefix "_" $name "_t*) items);
// Check that it contains 2 items.
assert(vector.size == 2);
// Free it.
wasm_" $name "_vec_delete(&vector);
" $prefix "_" $name "_vec_delete(&vector);
}
# })
# .success();
@@ -75,12 +83,12 @@ int main() {
```"]
#[derive(Debug)]
#[repr(C)]
pub struct [<wasm_ $name _vec_t>] {
pub struct [<$prefix _ $name _vec_t>] {
pub size: usize,
pub data: *mut [<wasm_ $name _t>],
pub data: *mut [<$prefix _ $name _t>],
}
impl Clone for [<wasm_ $name _vec_t>] {
impl Clone for [<$prefix _ $name _vec_t>] {
fn clone(&self) -> Self {
if self.data.is_null() {
return Self {
@@ -107,8 +115,8 @@ int main() {
}
}
impl<'a> From<Vec<[<wasm_ $name _t>]>> for [<wasm_ $name _vec_t>] {
fn from(mut vec: Vec<[<wasm_ $name _t>]>) -> Self {
impl<'a> From<Vec<[<$prefix _ $name _t>]>> for [<$prefix _ $name _vec_t>] {
fn from(mut vec: Vec<[<$prefix _ $name _t>]>) -> Self {
vec.shrink_to_fit();
let length = vec.len();
@@ -123,14 +131,14 @@ int main() {
}
}
impl<'a, T: Into<[<wasm_ $name _t>]> + Clone> From<&'a [T]> for [<wasm_ $name _vec_t>] {
impl<'a, T: Into<[<$prefix _ $name _t>]> + Clone> From<&'a [T]> for [<$prefix _ $name _vec_t>] {
fn from(other: &'a [T]) -> Self {
let size = other.len();
let mut copied_data = other
.iter()
.cloned()
.map(Into::into)
.collect::<Vec<[<wasm_ $name _t>]>>()
.collect::<Vec<[<$prefix _ $name _t>]>>()
.into_boxed_slice();
let data = copied_data.as_mut_ptr();
::std::mem::forget(copied_data);
@@ -142,8 +150,8 @@ int main() {
}
}
impl [<wasm_ $name _vec_t>] {
pub unsafe fn into_slice(&self) -> Option<&[[<wasm_ $name _t>]]>{
impl [<$prefix _ $name _vec_t>] {
pub unsafe fn into_slice(&self) -> Option<&[[<$prefix _ $name _t>]]>{
if self.is_uninitialized() {
return None;
}
@@ -151,7 +159,7 @@ int main() {
Some(::std::slice::from_raw_parts(self.data, self.size))
}
pub unsafe fn into_slice_mut(&mut self) -> Option<&mut [[<wasm_ $name _t>]]>{
pub unsafe fn into_slice_mut(&mut self) -> Option<&mut [[<$prefix _ $name _t>]]>{
if self.is_uninitialized() {
return None;
}
@@ -165,14 +173,14 @@ int main() {
}
// TODO: investigate possible memory leak on `init` (owned pointer)
#[doc = "Creates a new vector of [`wasm_" $name "_t`].
#[doc = "Creates a new vector of [`" $prefix "_" $name "_t`].
# Example
See the [`wasm_" $name "_vec_t`] type to get an example."]
See the [`" $prefix "_" $name "_vec_t`] type to get an example."]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *mut [<wasm_ $name _t>]) {
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length);
pub unsafe extern "C" fn [<$prefix _ $name _vec_new>](out: *mut [<$prefix _ $name _vec_t>], length: usize, init: *mut [<$prefix _ $name _t>]) {
let mut bytes: Vec<[<$prefix _ $name _t>]> = Vec::with_capacity(length);
for i in 0..length {
bytes.push(::std::ptr::read(init.add(i)));
@@ -186,7 +194,7 @@ See the [`wasm_" $name "_vec_t`] type to get an example."]
::std::mem::forget(bytes);
}
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`].
#[doc = "Creates a new uninitialized vector of [`" $prefix "_" $name "_t`].
# Example
@@ -197,23 +205,23 @@ See the [`wasm_" $name "_vec_t`] type to get an example."]
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Creates an empty vector of `wasm_" $name "_t`.
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new_uninitialized(&vector, 3);
// Creates an empty vector of `" $prefix "_" $name "_t`.
" $prefix "_" $name "_vec_t vector;
" $prefix "_" $name "_vec_new_uninitialized(&vector, 3);
// Check that it contains 3 items.
assert(vector.size == 3);
// Free it.
wasm_" $name "_vec_delete(&vector);
" $prefix "_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) {
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length);
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_uninitialized>](out: *mut [<$prefix _ $name _vec_t>], length: usize) {
let mut bytes: Vec<[<$prefix _ $name _t>]> = Vec::with_capacity(length);
let pointer = bytes.as_mut_ptr();
(*out).data = pointer;
@@ -222,22 +230,22 @@ int main() {
::std::mem::forget(bytes);
}
#[doc = "Performs a deep copy of a vector of [`wasm_" $name "_t`]."]
#[doc = "Performs a deep copy of a vector of [`" $prefix "_" $name "_t`]."]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_copy>](
out_ptr: &mut [<wasm_ $name _vec_t>],
pub unsafe extern "C" fn [<$prefix _ $name _vec_copy>](
out_ptr: &mut [<$prefix _ $name _vec_t>],
in_ptr: & [<wasm _$name _vec_t>])
{
*out_ptr = in_ptr.clone();
}
#[doc = "Deletes a vector of [`wasm_" $name "_t`].
#[doc = "Deletes a vector of [`" $prefix "_" $name "_t`].
# Example
See the [`wasm_" $name "_vec_t`] type to get an example."]
See the [`" $prefix "_" $name "_vec_t`] type to get an example."]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut [<wasm_ $name _vec_t>]>) {
pub unsafe extern "C" fn [<$prefix _ $name _vec_delete>](ptr: Option<&mut [<$prefix _ $name _vec_t>]>) {
if let Some(vec) = ptr {
if !vec.data.is_null() {
Vec::from_raw_parts(vec.data, vec.size, vec.size);
@@ -248,7 +256,7 @@ See the [`wasm_" $name "_vec_t`] type to get an example."]
}
}
wasm_declare_vec_inner!($name);
wasm_declare_vec_inner!($name, $prefix);
};
}
@@ -256,18 +264,22 @@ See the [`wasm_" $name "_vec_t`] type to get an example."]
#[macro_export]
macro_rules! wasm_declare_boxed_vec {
($name:ident) => {
paste::paste! {
#[doc = "Represents a vector of `wasm_" $name "_t`.
wasm_declare_boxed_vec!($name, wasm);
};
Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
($name:ident, $prefix:ident) => {
paste::paste! {
#[doc = "Represents a vector of `" $prefix "_" $name "_t`.
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples."]
#[derive(Debug)]
#[repr(C)]
pub struct [<wasm_ $name _vec_t>] {
pub struct [<$prefix _ $name _vec_t>] {
pub size: usize,
pub data: *mut *mut [<wasm_ $name _t>],
pub data: *mut *mut [<$prefix _ $name _t>],
}
impl Clone for [<wasm_ $name _vec_t>] {
impl Clone for [<$prefix _ $name _vec_t>] {
fn clone(&self) -> Self {
if self.data.is_null() {
return Self {
@@ -277,10 +289,10 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
}
let data =
unsafe {
let data: *mut Option<Box<[<wasm_ $name _t>]>> = self.data as _;
let data: *mut Option<Box<[<$prefix _ $name _t>]>> = self.data as _;
let vec = Vec::from_raw_parts(data, self.size, self.size);
let mut vec_copy = vec.clone().into_boxed_slice();
let new_ptr = vec_copy.as_mut_ptr() as *mut *mut [<wasm_ $name _t>];
let new_ptr = vec_copy.as_mut_ptr() as *mut *mut [<$prefix _ $name _t>];
::std::mem::forget(vec);
::std::mem::forget(vec_copy);
@@ -295,10 +307,10 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
}
}
impl<'a> From<Vec<Box<[<wasm_ $name _t>]>>> for [<wasm_ $name _vec_t>] {
fn from(other: Vec<Box<[<wasm_ $name _t>]>>) -> Self {
let boxed_slice: Box<[Box<[<wasm_ $name _t>]>]> = other.into_boxed_slice();
let mut boxed_slice: Box<[*mut [<wasm_ $name _t>]]> = unsafe { ::std::mem::transmute(boxed_slice) };
impl<'a> From<Vec<Box<[<$prefix _ $name _t>]>>> for [<$prefix _ $name _vec_t>] {
fn from(other: Vec<Box<[<$prefix _ $name _t>]>>) -> Self {
let boxed_slice: Box<[Box<[<$prefix _ $name _t>]>]> = other.into_boxed_slice();
let mut boxed_slice: Box<[*mut [<$prefix _ $name _t>]]> = unsafe { ::std::mem::transmute(boxed_slice) };
let size = boxed_slice.len();
let data = boxed_slice.as_mut_ptr();
@@ -310,7 +322,7 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
}
}
impl<'a, T: Into<[<wasm_ $name _t>]> + Clone> From<&'a [T]> for [<wasm_ $name _vec_t>] {
impl<'a, T: Into<[<$prefix _ $name _t>]> + Clone> From<&'a [T]> for [<$prefix _ $name _vec_t>] {
fn from(other: &'a [T]) -> Self {
let size = other.len();
let mut copied_data = other
@@ -319,7 +331,7 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
.map(Into::into)
.map(Box::new)
.map(Box::into_raw)
.collect::<Vec<*mut [<wasm_ $name _t>]>>()
.collect::<Vec<*mut [<$prefix _ $name _t>]>>()
.into_boxed_slice();
let data = copied_data.as_mut_ptr();
::std::mem::forget(copied_data);
@@ -332,23 +344,23 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
}
// TODO: do this properly
impl [<wasm_ $name _vec_t>] {
pub unsafe fn into_slice(&self) -> Option<&[Box<[<wasm_ $name _t>]>]>{
impl [<$prefix _ $name _vec_t>] {
pub unsafe fn into_slice(&self) -> Option<&[Box<[<$prefix _ $name _t>]>]>{
if self.data.is_null() {
return None;
}
let slice: &[*mut [<wasm_ $name _t>]] = ::std::slice::from_raw_parts(self.data, self.size);
let slice: &[Box<[<wasm_ $name _t>]>] = ::std::mem::transmute(slice);
let slice: &[*mut [<$prefix _ $name _t>]] = ::std::slice::from_raw_parts(self.data, self.size);
let slice: &[Box<[<$prefix _ $name _t>]>] = ::std::mem::transmute(slice);
Some(slice)
}
}
// TODO: investigate possible memory leak on `init` (owned pointer)
#[doc = "Creates a new vector of [`wasm_" $name "_t`]."]
#[doc = "Creates a new vector of [`" $prefix "_" $name "_t`]."]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *const *mut [<wasm_ $name _t>]) {
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length);
pub unsafe extern "C" fn [<$prefix _ $name _vec_new>](out: *mut [<$prefix _ $name _vec_t>], length: usize, init: *const *mut [<$prefix _ $name _t>]) {
let mut bytes: Vec<*mut [<$prefix _ $name _t>]> = Vec::with_capacity(length);
for i in 0..length {
bytes.push(*init.add(i));
@@ -363,7 +375,7 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
::std::mem::forget(boxed_vec);
}
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`].
#[doc = "Creates a new uninitialized vector of [`" $prefix "_" $name "_t`].
# Example
@@ -374,23 +386,23 @@ Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Creates an empty vector of `wasm_" $name "_t`.
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new_uninitialized(&vector, 3);
// Creates an empty vector of `" $prefix "_" $name "_t`.
" $prefix "_" $name "_vec_t vector;
" $prefix "_" $name "_vec_new_uninitialized(&vector, 3);
// Check that it contains 3 items.
assert(vector.size == 3);
// Free it.
wasm_" $name "_vec_delete(&vector);
" $prefix "_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) {
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = vec![::std::ptr::null_mut(); length];
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_uninitialized>](out: *mut [<$prefix _ $name _vec_t>], length: usize) {
let mut bytes: Vec<*mut [<$prefix _ $name _t>]> = vec![::std::ptr::null_mut(); length];
let pointer = bytes.as_mut_ptr();
(*out).data = pointer;
@@ -399,26 +411,26 @@ int main() {
::std::mem::forget(bytes);
}
#[doc = "Performs a deep copy of a vector of [`wasm_" $name "_t`]."]
#[doc = "Performs a deep copy of a vector of [`" $prefix "_" $name "_t`]."]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_copy>](
out_ptr: &mut [<wasm_ $name _vec_t>],
in_ptr: & [<wasm_ $name _vec_t>])
pub unsafe extern "C" fn [<$prefix _ $name _vec_copy>](
out_ptr: &mut [<$prefix _ $name _vec_t>],
in_ptr: & [<$prefix _ $name _vec_t>])
{
*out_ptr = in_ptr.clone();
}
#[doc = "Deletes a vector of [`wasm_" $name "_t`].
#[doc = "Deletes a vector of [`" $prefix "_" $name "_t`].
# Example
See the [`wasm_" $name "_vec_t`] type to get an example."]
See the [`" $prefix "_" $name "_vec_t`] type to get an example."]
#[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut [<wasm_ $name _vec_t>]>) {
pub unsafe extern "C" fn [<$prefix _ $name _vec_delete>](ptr: Option<&mut [<$prefix _ $name _vec_t>]>) {
if let Some(vec) = ptr {
if !vec.data.is_null() {
let data = vec.data as *mut Option<Box<[<wasm_ $name _t>]>>;
let _data: Vec<Option<Box<[<wasm_ $name _t>]>>> = Vec::from_raw_parts(data, vec.size, vec.size);
let data = vec.data as *mut Option<Box<[<$prefix _ $name _t>]>>;
let _data: Vec<Option<Box<[<$prefix _ $name _t>]>>> = Vec::from_raw_parts(data, vec.size, vec.size);
vec.data = ::std::ptr::null_mut();
vec.size = 0;
@@ -427,7 +439,7 @@ See the [`wasm_" $name "_vec_t`] type to get an example."]
}
}
wasm_declare_vec_inner!($name);
wasm_declare_vec_inner!($name, $prefix);
};
}
@@ -435,11 +447,15 @@ See the [`wasm_" $name "_vec_t`] type to get an example."]
#[macro_export]
macro_rules! wasm_declare_ref_base {
($name:ident) => {
wasm_declare_own!($name);
wasm_declare_ref_base!($name, wasm);
};
($name:ident, $prefix:ident) => {
wasm_declare_own!($name, $prefix);
paste::paste! {
#[no_mangle]
pub extern "C" fn [<wasm_ $name _copy>](_arg: *const [<wasm_ $name _t>]) -> *mut [<wasm_ $name _t>] {
pub extern "C" fn [<$prefix _ $name _copy>](_arg: *const [<$prefix _ $name _t>]) -> *mut [<$prefix _ $name _t>] {
todo!("in generated declare ref base");
//ptr::null_mut()
}
@@ -453,12 +469,16 @@ macro_rules! wasm_declare_ref_base {
#[macro_export]
macro_rules! wasm_declare_own {
($name:ident) => {
wasm_declare_own!($name, $prefix);
};
($name:ident, $prefix:ident) => {
paste::paste! {
#[repr(C)]
pub struct [<wasm_ $name _t>] {}
pub struct [<$prefix _ $name _t>] {}
#[no_mangle]
pub extern "C" fn [<wasm_ $name _delete>](_arg: *mut [<wasm_ $name _t>]) {
pub extern "C" fn [<$prefix _ $name _delete>](_arg: *mut [<$prefix _ $name _t>]) {
todo!("in generated delete")
}
}

View File

@@ -1,8 +1,8 @@
//! Unstable non-standard Wasmer-specific types for the
//! `wasm_engine_t` and siblings.
use super::super::engine::wasm_config_t;
use super::target_lexicon::wasm_target_t;
use super::super::engine::{wasm_config_t, wasmer_compiler_t, wasmer_engine_t};
use super::target_lexicon::wasmer_target_t;
/// Unstable non-standard Wasmer-specific API to update the
/// configuration to specify a particular target for the engine.
@@ -21,9 +21,9 @@ use super::target_lexicon::wasm_target_t;
///
/// // Set the target.
/// {
/// wasm_triple_t* triple = wasm_triple_new_from_host();
/// wasm_cpu_features_t* cpu_features = wasm_cpu_features_new();
/// wasm_target_t* target = wasm_target_new(triple, cpu_features);
/// wasmer_triple_t* triple = wasmer_triple_new_from_host();
/// wasmer_cpu_features_t* cpu_features = wasmer_cpu_features_new();
/// wasmer_target_t* target = wasmer_target_new(triple, cpu_features);
///
/// wasm_config_set_target(config, target);
/// }
@@ -44,6 +44,136 @@ use super::target_lexicon::wasm_target_t;
/// # }
/// ```
#[no_mangle]
pub extern "C" fn wasm_config_set_target(config: &mut wasm_config_t, target: Box<wasm_target_t>) {
pub extern "C" fn wasm_config_set_target(config: &mut wasm_config_t, target: Box<wasmer_target_t>) {
config.target = Some(target);
}
/// Check whether the given compiler is available, i.e. part of this
/// compiled library.
#[no_mangle]
pub extern "C" fn wasmer_is_compiler_available(compiler: wasmer_compiler_t) -> bool {
match compiler {
wasmer_compiler_t::CRANELIFT if cfg!(feature = "cranelift") => true,
wasmer_compiler_t::LLVM if cfg!(feature = "llvm") => true,
wasmer_compiler_t::SINGLEPASS if cfg!(feature = "singlepass") => true,
_ => false,
}
}
/// Check whether there is no compiler available in this compiled
/// library.
#[no_mangle]
pub extern "C" fn wasmer_is_headless() -> bool {
!cfg!(feature = "compiler")
}
/// Check whether the given engine is available, i.e. part of this
/// compiled library.
#[no_mangle]
pub extern "C" fn wasmer_is_engine_available(engine: wasmer_engine_t) -> bool {
match engine {
wasmer_engine_t::JIT if cfg!(feature = "jit") => true,
wasmer_engine_t::NATIVE if cfg!(feature = "native") => true,
wasmer_engine_t::OBJECT_FILE if cfg!(feature = "object-file") => true,
_ => false,
}
}
#[cfg(test)]
mod tests {
use inline_c::assert_c;
use std::env::{remove_var, set_var};
#[test]
fn test_wasmer_is_headless() {
set_var(
"COMPILER",
if cfg!(feature = "compiler") { "0" } else { "1" },
);
(assert_c! {
#include "tests/wasmer_wasm.h"
#include <stdlib.h>
int main() {
assert(wasmer_is_headless() == (getenv("COMPILER")[0] == '1'));
return 0;
}
})
.success();
remove_var("COMPILER");
}
#[test]
fn test_wasmer_is_compiler_available() {
set_var(
"CRANELIFT",
if cfg!(feature = "cranelift") {
"1"
} else {
"0"
},
);
set_var("LLVM", if cfg!(feature = "llvm") { "1" } else { "0" });
set_var(
"SINGLEPASS",
if cfg!(feature = "singlepass") {
"1"
} else {
"0"
},
);
(assert_c! {
#include "tests/wasmer_wasm.h"
#include <stdlib.h>
int main() {
assert(wasmer_is_compiler_available(CRANELIFT) == (getenv("CRANELIFT")[0] == '1'));
assert(wasmer_is_compiler_available(LLVM) == (getenv("LLVM")[0] == '1'));
assert(wasmer_is_compiler_available(SINGLEPASS) == (getenv("SINGLEPASS")[0] == '1'));
return 0;
}
})
.success();
remove_var("CRANELIFT");
remove_var("LLVM");
remove_var("SINGLEPASS");
}
#[test]
fn test_wasmer_is_engine_available() {
set_var("JIT", if cfg!(feature = "jit") { "1" } else { "0" });
set_var("NATIVE", if cfg!(feature = "native") { "1" } else { "0" });
set_var(
"OBJECT_FILE",
if cfg!(feature = "object-file") {
"1"
} else {
"0"
},
);
(assert_c! {
#include "tests/wasmer_wasm.h"
#include <stdlib.h>
int main() {
assert(wasmer_is_engine_available(JIT) == (getenv("JIT")[0] == '1'));
assert(wasmer_is_engine_available(NATIVE) == (getenv("NATIVE")[0] == '1'));
assert(wasmer_is_engine_available(OBJECT_FILE) == (getenv("OBJECT_FILE")[0] == '1'));
return 0;
}
})
.success();
remove_var("JIT");
remove_var("NATIVE");
remove_var("OBJECT_FILE");
}
}

View File

@@ -3,3 +3,6 @@ pub mod engine;
pub mod middlewares;
pub mod module;
pub mod target_lexicon;
#[cfg(feature = "wasi")]
pub mod wasi;

View File

@@ -35,7 +35,7 @@ use std::sync::Arc;
///
/// // Read the module's name.
/// wasm_name_t name;
/// wasm_module_name(module, &name);
/// wasmer_module_name(module, &name);
///
/// // It works!
/// wasmer_assert_name(&name, "moduleName");
@@ -55,7 +55,7 @@ use std::sync::Arc;
/// # }
/// ```
#[no_mangle]
pub unsafe extern "C" fn wasm_module_name(
pub unsafe extern "C" fn wasmer_module_name(
module: &wasm_module_t,
// own
out: &mut wasm_name_t,
@@ -102,7 +102,7 @@ pub unsafe extern "C" fn wasm_module_name(
/// // Read the module's name. There is none for the moment.
/// {
/// wasm_name_t name;
/// wasm_module_name(module, &name);
/// wasmer_module_name(module, &name);
///
/// assert(name.size == 0);
/// }
@@ -111,13 +111,13 @@ pub unsafe extern "C" fn wasm_module_name(
/// {
/// wasm_name_t name;
/// wasmer_byte_vec_new_from_string(&name, "hello");
/// wasm_module_set_name(module, &name);
/// wasmer_module_set_name(module, &name);
/// }
///
/// // And now, let's see the new name.
/// {
/// wasm_name_t name;
/// wasm_module_name(module, &name);
/// wasmer_module_name(module, &name);
///
/// // It works!
/// wasmer_assert_name(&name, "hello");
@@ -139,7 +139,7 @@ pub unsafe extern "C" fn wasm_module_name(
/// # }
/// ```
#[no_mangle]
pub unsafe extern "C" fn wasm_module_set_name(
pub unsafe extern "C" fn wasmer_module_set_name(
module: &mut wasm_module_t,
// own
name: &wasm_name_t,

View File

@@ -13,13 +13,13 @@
//! #
//! int main() {
//! // Declare the target triple.
//! wasm_triple_t* triple;
//! wasmer_triple_t* triple;
//!
//! {
//! wasm_name_t triple_name;
//! wasm_name_new_from_string(&triple_name, "x86_64-apple-darwin");
//!
//! triple = wasm_triple_new(&triple_name);
//! triple = wasmer_triple_new(&triple_name);
//!
//! wasm_name_delete(&triple_name);
//! }
@@ -27,13 +27,13 @@
//! assert(triple);
//!
//! // Declare the target CPU features.
//! wasm_cpu_features_t* cpu_features = wasm_cpu_features_new();
//! wasmer_cpu_features_t* cpu_features = wasmer_cpu_features_new();
//!
//! {
//! wasm_name_t cpu_feature_name;
//! wasm_name_new_from_string(&cpu_feature_name, "sse2");
//!
//! wasm_cpu_features_add(cpu_features, &cpu_feature_name);
//! wasmer_cpu_features_add(cpu_features, &cpu_feature_name);
//!
//! wasm_name_delete(&cpu_feature_name);
//! }
@@ -41,10 +41,10 @@
//! assert(cpu_features);
//!
//! // Create the target!
//! wasm_target_t* target = wasm_target_new(triple, cpu_features);
//! wasmer_target_t* target = wasmer_target_new(triple, cpu_features);
//! assert(target);
//!
//! wasm_target_delete(target);
//! wasmer_target_delete(target);
//!
//! return 0;
//! }
@@ -68,11 +68,11 @@ use wasmer_compiler::{CpuFeature, Target, Triple};
/// See the module's documentation.
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct wasm_target_t {
pub struct wasmer_target_t {
pub(crate) inner: Target,
}
/// Creates a new [`wasm_target_t`].
/// Creates a new [`wasmer_target_t`].
///
/// It takes ownership of `triple` and `cpu_features`.
///
@@ -80,25 +80,25 @@ pub struct wasm_target_t {
///
/// See the module's documentation.
#[no_mangle]
pub extern "C" fn wasm_target_new(
triple: Option<Box<wasm_triple_t>>,
cpu_features: Option<Box<wasm_cpu_features_t>>,
) -> Option<Box<wasm_target_t>> {
pub extern "C" fn wasmer_target_new(
triple: Option<Box<wasmer_triple_t>>,
cpu_features: Option<Box<wasmer_cpu_features_t>>,
) -> Option<Box<wasmer_target_t>> {
let triple = triple?;
let cpu_features = cpu_features?;
Some(Box::new(wasm_target_t {
Some(Box::new(wasmer_target_t {
inner: Target::new(triple.inner.clone(), cpu_features.inner.clone()),
}))
}
/// Delete a [`wasm_target_t`].
/// Delete a [`wasmer_target_t`].
///
/// # Example
///
/// See the module's documentation.
#[no_mangle]
pub extern "C" fn wasm_target_delete(_target: Option<Box<wasm_target_t>>) {}
pub extern "C" fn wasmer_target_delete(_target: Option<Box<wasmer_target_t>>) {}
/// Unstable non-standard Wasmer-specific API to represent a target
/// “triple”.
@@ -118,10 +118,10 @@ pub extern "C" fn wasm_target_delete(_target: Option<Box<wasm_target_t>>) {}
/// wasm_name_t triple_name;
/// wasm_name_new_from_string(&triple_name, "x86_64-apple-darwin");
///
/// wasm_triple_t* triple = wasm_triple_new(&triple_name);
/// wasmer_triple_t* triple = wasmer_triple_new(&triple_name);
/// assert(triple);
///
/// wasm_triple_delete(triple);
/// wasmer_triple_delete(triple);
/// wasm_name_delete(&triple_name);
///
/// return 0;
@@ -131,33 +131,33 @@ pub extern "C" fn wasm_target_delete(_target: Option<Box<wasm_target_t>>) {}
/// # }
/// ```
///
/// See also [`wasm_triple_new_from_host`].
/// See also [`wasmer_triple_new_from_host`].
#[allow(non_camel_case_types)]
pub struct wasm_triple_t {
pub struct wasmer_triple_t {
inner: Triple,
}
/// Create a new [`wasm_triple_t`] based on a triple string.
/// Create a new [`wasmer_triple_t`] based on a triple string.
///
/// # Example
///
/// See [`wasm_triple_t`] or [`wasm_triple_new_from_host`].
/// See [`wasmer_triple_t`] or [`wasmer_triple_new_from_host`].
#[no_mangle]
pub unsafe extern "C" fn wasm_triple_new(
pub unsafe extern "C" fn wasmer_triple_new(
triple: Option<&wasm_name_t>,
) -> Option<Box<wasm_triple_t>> {
) -> Option<Box<wasmer_triple_t>> {
let triple = triple?;
let triple = c_try!(str::from_utf8(slice::from_raw_parts(
triple.data,
triple.size
)));
Some(Box::new(wasm_triple_t {
Some(Box::new(wasmer_triple_t {
inner: c_try!(Triple::from_str(triple).map_err(|e| CApiError { msg: e.to_string() })),
}))
}
/// Create the [`wasm_triple_t`] for the current host.
/// Create the [`wasmer_triple_t`] for the current host.
///
/// # Example
///
@@ -168,10 +168,10 @@ pub unsafe extern "C" fn wasm_triple_new(
/// # #include "tests/wasmer_wasm.h"
/// #
/// int main() {
/// wasm_triple_t* triple = wasm_triple_new_from_host();
/// wasmer_triple_t* triple = wasmer_triple_new_from_host();
/// assert(triple);
///
/// wasm_triple_delete(triple);
/// wasmer_triple_delete(triple);
///
/// return 0;
/// }
@@ -180,21 +180,21 @@ pub unsafe extern "C" fn wasm_triple_new(
/// # }
/// ```
///
/// See also [`wasm_triple_new`].
/// See also [`wasmer_triple_new`].
#[no_mangle]
pub extern "C" fn wasm_triple_new_from_host() -> Box<wasm_triple_t> {
Box::new(wasm_triple_t {
pub extern "C" fn wasmer_triple_new_from_host() -> Box<wasmer_triple_t> {
Box::new(wasmer_triple_t {
inner: Triple::host(),
})
}
/// Delete a [`wasm_triple_t`].
/// Delete a [`wasmer_triple_t`].
///
/// # Example
///
/// See [`wasm_triple_t`].
/// See [`wasmer_triple_t`].
#[no_mangle]
pub extern "C" fn wasm_triple_delete(_triple: Option<Box<wasm_triple_t>>) {}
pub extern "C" fn wasmer_triple_delete(_triple: Option<Box<wasmer_triple_t>>) {}
/// Unstable non-standard Wasmer-specific API to represent a set of
/// CPU features.
@@ -233,19 +233,19 @@ pub extern "C" fn wasm_triple_delete(_triple: Option<Box<wasm_triple_t>>) {}
/// #
/// int main() {
/// // Create a new CPU feature set.
/// wasm_cpu_features_t* cpu_features = wasm_cpu_features_new();
/// wasmer_cpu_features_t* cpu_features = wasmer_cpu_features_new();
///
/// // Create a new feature name, here `sse2`, and add it to the set.
/// {
/// wasm_name_t cpu_feature_name;
/// wasm_name_new_from_string(&cpu_feature_name, "sse2");
///
/// wasm_cpu_features_add(cpu_features, &cpu_feature_name);
/// wasmer_cpu_features_add(cpu_features, &cpu_feature_name);
///
/// wasm_name_delete(&cpu_feature_name);
/// }
///
/// wasm_cpu_features_delete(cpu_features);
/// wasmer_cpu_features_delete(cpu_features);
///
/// return 0;
/// }
@@ -254,39 +254,39 @@ pub extern "C" fn wasm_triple_delete(_triple: Option<Box<wasm_triple_t>>) {}
/// # }
/// ```
#[allow(non_camel_case_types)]
pub struct wasm_cpu_features_t {
pub struct wasmer_cpu_features_t {
inner: EnumSet<CpuFeature>,
}
/// Create a new [`wasm_cpu_features_t`].
/// Create a new [`wasmer_cpu_features_t`].
///
/// # Example
///
/// See [`wasm_cpu_features_t`].
/// See [`wasmer_cpu_features_t`].
#[no_mangle]
pub extern "C" fn wasm_cpu_features_new() -> Box<wasm_cpu_features_t> {
Box::new(wasm_cpu_features_t {
pub extern "C" fn wasmer_cpu_features_new() -> Box<wasmer_cpu_features_t> {
Box::new(wasmer_cpu_features_t {
inner: CpuFeature::set(),
})
}
/// Delete a [`wasm_cpu_features_t`].
/// Delete a [`wasmer_cpu_features_t`].
///
/// # Example
///
/// See [`wasm_cpu_features_t`].
/// See [`wasmer_cpu_features_t`].
#[no_mangle]
pub extern "C" fn wasm_cpu_features_delete(_cpu_features: Option<Box<wasm_cpu_features_t>>) {}
pub extern "C" fn wasmer_cpu_features_delete(_cpu_features: Option<Box<wasmer_cpu_features_t>>) {}
/// Add a new CPU feature into the set represented by
/// [`wasm_cpu_features_t`].
/// [`wasmer_cpu_features_t`].
///
/// # Example
///
/// See [`wasm_cpu_features_t`].
/// See [`wasmer_cpu_features_t`].
#[no_mangle]
pub unsafe extern "C" fn wasm_cpu_features_add(
cpu_features: Option<&mut wasm_cpu_features_t>,
pub unsafe extern "C" fn wasmer_cpu_features_add(
cpu_features: Option<&mut wasmer_cpu_features_t>,
feature: Option<&wasm_name_t>,
) -> bool {
let cpu_features = match cpu_features {

View File

@@ -0,0 +1,199 @@
//! Unstable non-standard Wasmer-specific API that contains more WASI
//! API.
use super::super::{
externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t,
wasi::wasi_env_t,
};
use crate::error::CApiError;
use wasmer::Extern;
use wasmer_wasi::{generate_import_object_from_env, get_wasi_version};
/// Unstable non-standard type wrapping `wasm_extern_t` with the
/// addition of two `wasm_name_t` respectively for the module name and
/// the name of the extern (very likely to be an import). This
/// non-standard type is used by the unstable non-standard
/// `wasi_get_unordered_imports` function.
///
/// The `module`, `name` and `extern` fields are all owned by this type.
#[allow(non_camel_case_types)]
#[derive(Clone)]
pub struct wasmer_named_extern_t {
module: Box<wasm_name_t>,
name: Box<wasm_name_t>,
r#extern: Box<wasm_extern_t>,
}
wasm_declare_boxed_vec!(named_extern, wasmer);
/// So. Let's explain a dirty hack. `cbindgen` reads the code and
/// collects symbols. What symbols do we need? None of the one
/// declared in `wasm.h`, but for non-standard API, we need to collect
/// all of them. The problem is that `wasmer_named_extern_t` is the only
/// non-standard type where extra symbols are generated by a macro
/// (`wasm_declare_boxed_vec!`). If we want those macro-generated
/// symbols to be collected by `cbindgen`, we need to _expand_ the
/// crate (i.e. running something like `rustc -- -Zunstable-options
/// --pretty=expanded`). Expanding code is unstable and available only
/// on nightly compiler. We _don't want_ to use a nightly compiler
/// only for that. So how can we help `cbindgen` to _see_ those
/// symbols?
///
/// First solution: We write the C code directly in a file, which is
/// then included in the generated header file with the `cbindgen`
/// API. Problem, it's super easy to get it outdated, and it makes the
/// build process more complex.
///
/// Second solution: We write those symbols in a custom module, that
/// is just here for `cbindgen`, never used by our Rust code
/// (otherwise it's duplicated code), with no particular
/// implementation.
///
/// And that's why we have the following `cbindgen_hack`
/// module.
///
/// But this module must not be compiled by `rustc`. How to force
/// `rustc` to ignore a module? With conditional compilation. Because
/// `cbindgen` does not support conditional compilation, it will
/// always _ignore_ the `#[cfg]` attribute, and will always read the
/// content of the module.
///
/// Sorry.
#[doc(hidden)]
#[cfg(__cbindgen_hack__ = "yes")]
mod __cbindgen_hack__ {
use super::*;
#[repr(C)]
pub struct wasmer_named_extern_vec_t {
pub size: usize,
pub data: *mut *mut wasmer_named_extern_t,
}
#[no_mangle]
pub unsafe extern "C" fn wasmer_named_extern_vec_new(
out: *mut wasmer_named_extern_vec_t,
length: usize,
init: *const *mut wasmer_named_extern_t,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasmer_named_extern_vec_new_uninitialized(
out: *mut wasmer_named_extern_vec_t,
length: usize,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasmer_named_extern_vec_copy(
out_ptr: &mut wasmer_named_extern_vec_t,
in_ptr: &wasmer_named_extern_vec_t,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasmer_named_extern_vec_delete(
ptr: Option<&mut wasmer_named_extern_vec_t>,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasmer_named_extern_vec_new_empty(
out: *mut wasmer_named_extern_vec_t,
) {
unimplemented!()
}
}
/// Non-standard function to get the module name of a
/// `wasmer_named_extern_t`.
///
/// The returned value isn't owned by the caller.
#[no_mangle]
pub extern "C" fn wasmer_named_extern_module(
named_extern: Option<&wasmer_named_extern_t>,
) -> Option<&wasm_name_t> {
Some(named_extern?.module.as_ref())
}
/// Non-standard function to get the name of a `wasmer_named_extern_t`.
///
/// The returned value isn't owned by the caller.
#[no_mangle]
pub extern "C" fn wasmer_named_extern_name(
named_extern: Option<&wasmer_named_extern_t>,
) -> Option<&wasm_name_t> {
Some(named_extern?.name.as_ref())
}
/// Non-standard function to get the wrapped extern of a
/// `wasmer_named_extern_t`.
///
/// The returned value isn't owned by the caller.
#[no_mangle]
pub extern "C" fn wasmer_named_extern_unwrap(
named_extern: Option<&wasmer_named_extern_t>,
) -> Option<&wasm_extern_t> {
Some(named_extern?.r#extern.as_ref())
}
/// Non-standard function to get the imports needed for the WASI
/// implementation with no particular order. Each import has its
/// associated module name and name, so that it can be re-order later
/// based on the `wasm_module_t` requirements.
#[no_mangle]
pub unsafe extern "C" fn wasi_get_unordered_imports(
store: Option<&wasm_store_t>,
module: Option<&wasm_module_t>,
wasi_env: Option<&wasi_env_t>,
imports: &mut wasmer_named_extern_vec_t,
) -> bool {
wasi_get_unordered_imports_inner(store, module, wasi_env, imports).is_some()
}
fn wasi_get_unordered_imports_inner(
store: Option<&wasm_store_t>,
module: Option<&wasm_module_t>,
wasi_env: Option<&wasi_env_t>,
imports: &mut wasmer_named_extern_vec_t,
) -> Option<()> {
let store = store?;
let module = module?;
let wasi_env = wasi_env?;
let store = &store.inner;
let version = c_try!(
get_wasi_version(&module.inner, false).ok_or_else(|| CApiError {
msg: "could not detect a WASI version on the given module".to_string(),
})
);
let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);
*imports = import_object
.into_iter()
.map(|((module, name), export)| {
let module = Box::new(module.into());
let name = Box::new(name.into());
let extern_inner = Extern::from_vm_export(store, export);
Box::new(wasmer_named_extern_t {
module,
name,
r#extern: Box::new(wasm_extern_t {
instance: None,
inner: extern_inner,
}),
})
})
.collect::<Vec<_>>()
.into();
Some(())
}

View File

@@ -4,15 +4,13 @@
mod capture_files;
pub use super::unstable::wasi::wasi_get_unordered_imports;
use super::{
externals::{wasm_extern_t, wasm_extern_vec_t, wasm_func_t, wasm_memory_t},
instance::wasm_instance_t,
module::wasm_module_t,
store::wasm_store_t,
types::wasm_name_t,
};
// required due to really weird Rust resolution rules for macros
// https://github.com/rust-lang/rust/issues/57966
use crate::error::{update_last_error, CApiError};
use std::cmp::min;
use std::convert::TryFrom;
@@ -168,7 +166,7 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) {
#[allow(non_camel_case_types)]
pub struct wasi_env_t {
/// cbindgen:ignore
inner: WasiEnv,
pub(super) inner: WasiEnv,
}
/// Create a new WASI environment.
@@ -345,192 +343,6 @@ pub unsafe extern "C" fn wasi_get_wasi_version(module: &wasm_module_t) -> wasi_v
.unwrap_or(wasi_version_t::INVALID_VERSION)
}
/// Non-standard type wrapping `wasm_extern_t` with the addition of
/// two `wasm_name_t` respectively for the module name and the name of
/// the extern (very likely to be an import). This non-standard type
/// is used by the non-standard `wasi_get_unordered_imports` function.
///
/// The `module`, `name` and `extern` fields are all owned by this type.
#[allow(non_camel_case_types)]
#[derive(Clone)]
pub struct wasm_named_extern_t {
module: Box<wasm_name_t>,
name: Box<wasm_name_t>,
r#extern: Box<wasm_extern_t>,
}
wasm_declare_boxed_vec!(named_extern);
/// So. Let's explain a dirty hack. `cbindgen` reads the code and
/// collects symbols. What symbols do we need? None of the one
/// declared in `wasm.h`, but for non-standard API, we need to collect
/// all of them. The problem is that `wasm_named_extern_t` is the only
/// non-standard type where extra symbols are generated by a macro
/// (`wasm_declare_boxed_vec!`). If we want those macro-generated
/// symbols to be collected by `cbindgen`, we need to _expand_ the
/// crate (i.e. running something like `rustc -- -Zunstable-options
/// --pretty=expanded`). Expanding code is unstable and available only
/// on nightly compiler. We _don't want_ to use a nightly compiler
/// only for that. So how can we help `cbindgen` to _see_ those
/// symbols?
///
/// First solution: We write the C code directly in a file, which is
/// then included in the generated header file with the `cbindgen`
/// API. Problem, it's super easy to get it outdated, and it makes the
/// build process more complex.
///
/// Second solution: We write those symbols in a custom module, that
/// is just here for `cbindgen`, never used by our Rust code
/// (otherwise it's duplicated code), with no particular
/// implementation.
///
/// And that's why we have the following `cbindgen_hack`
/// module.
///
/// But this module must not be compiled by `rustc`. How to force
/// `rustc` to ignore a module? With conditional compilation. Because
/// `cbindgen` does not support conditional compilation, it will
/// always _ignore_ the `#[cfg]` attribute, and will always read the
/// content of the module.
///
/// Sorry.
#[doc(hidden)]
#[cfg(__cbindgen_hack__ = "yes")]
mod __cbindgen_hack__ {
use super::*;
#[repr(C)]
pub struct wasm_named_extern_vec_t {
pub size: usize,
pub data: *mut *mut wasm_named_extern_t,
}
#[no_mangle]
pub unsafe extern "C" fn wasm_named_extern_vec_new(
out: *mut wasm_named_extern_vec_t,
length: usize,
init: *const *mut wasm_named_extern_t,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_named_extern_vec_new_uninitialized(
out: *mut wasm_named_extern_vec_t,
length: usize,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_named_extern_vec_copy(
out_ptr: &mut wasm_named_extern_vec_t,
in_ptr: &wasm_named_extern_vec_t,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_named_extern_vec_delete(
ptr: Option<&mut wasm_named_extern_vec_t>,
) {
unimplemented!()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_named_extern_vec_new_empty(out: *mut wasm_named_extern_vec_t) {
unimplemented!()
}
}
/// Non-standard function to get the module name of a
/// `wasm_named_extern_t`.
///
/// The returned value isn't owned by the caller.
#[no_mangle]
pub extern "C" fn wasm_named_extern_module(
named_extern: Option<&wasm_named_extern_t>,
) -> Option<&wasm_name_t> {
Some(named_extern?.module.as_ref())
}
/// Non-standard function to get the name of a `wasm_named_extern_t`.
///
/// The returned value isn't owned by the caller.
#[no_mangle]
pub extern "C" fn wasm_named_extern_name(
named_extern: Option<&wasm_named_extern_t>,
) -> Option<&wasm_name_t> {
Some(named_extern?.name.as_ref())
}
/// Non-standard function to get the wrapped extern of a
/// `wasm_named_extern_t`.
///
/// The returned value isn't owned by the caller.
#[no_mangle]
pub extern "C" fn wasm_named_extern_unwrap(
named_extern: Option<&wasm_named_extern_t>,
) -> Option<&wasm_extern_t> {
Some(named_extern?.r#extern.as_ref())
}
/// Non-standard function to get the imports needed for the WASI
/// implementation with no particular order. Each import has its
/// associated module name and name, so that it can be re-order later
/// based on the `wasm_module_t` requirements.
#[no_mangle]
pub unsafe extern "C" fn wasi_get_unordered_imports(
store: Option<&wasm_store_t>,
module: Option<&wasm_module_t>,
wasi_env: Option<&wasi_env_t>,
imports: &mut wasm_named_extern_vec_t,
) -> bool {
wasi_get_unordered_imports_inner(store, module, wasi_env, imports).is_some()
}
fn wasi_get_unordered_imports_inner(
store: Option<&wasm_store_t>,
module: Option<&wasm_module_t>,
wasi_env: Option<&wasi_env_t>,
imports: &mut wasm_named_extern_vec_t,
) -> Option<()> {
let store = store?;
let module = module?;
let wasi_env = wasi_env?;
let store = &store.inner;
let version = c_try!(
get_wasi_version(&module.inner, false).ok_or_else(|| CApiError {
msg: "could not detect a WASI version on the given module".to_string(),
})
);
let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);
*imports = import_object
.into_iter()
.map(|((module, name), export)| {
let module = Box::new(module.into());
let name = Box::new(name.into());
let extern_inner = Extern::from_vm_export(store, export);
Box::new(wasm_named_extern_t {
module,
name,
r#extern: Box::new(wasm_extern_t {
instance: None,
inner: extern_inner,
}),
})
})
.collect::<Vec<_>>()
.into();
Some(())
}
/// Non-standard function to get the imports needed for the WASI
/// implementation ordered as expected by the `wasm_module_t`.
#[no_mangle]

View File

@@ -134,15 +134,15 @@ typedef struct wasi_config_t wasi_config_t;
typedef struct wasi_env_t wasi_env_t;
#endif
typedef struct wasm_cpu_features_t wasm_cpu_features_t;
typedef struct wasmer_cpu_features_t wasmer_cpu_features_t;
#if defined(WASMER_WASI_ENABLED)
typedef struct wasm_named_extern_t wasm_named_extern_t;
typedef struct wasmer_named_extern_t wasmer_named_extern_t;
#endif
typedef struct wasm_target_t wasm_target_t;
typedef struct wasmer_target_t wasmer_target_t;
typedef struct wasm_triple_t wasm_triple_t;
typedef struct wasmer_triple_t wasmer_triple_t;
typedef struct wasmer_metering_points_t wasmer_metering_points_t;
@@ -153,8 +153,8 @@ typedef struct wasmer_module_middleware_t wasmer_module_middleware_t;
#if defined(WASMER_WASI_ENABLED)
typedef struct {
uintptr_t size;
wasm_named_extern_t **data;
} wasm_named_extern_vec_t;
wasmer_named_extern_t **data;
} wasmer_named_extern_vec_t;
#endif
#ifdef __cplusplus
@@ -244,7 +244,7 @@ wasm_func_t *wasi_get_start_function(wasm_instance_t *instance);
bool wasi_get_unordered_imports(const wasm_store_t *store,
const wasm_module_t *module,
const wasi_env_t *wasi_env,
wasm_named_extern_vec_t *imports);
wasmer_named_extern_vec_t *imports);
#endif
#if defined(WASMER_WASI_ENABLED)
@@ -259,67 +259,73 @@ void wasm_config_set_compiler(wasm_config_t *config, wasmer_compiler_t compiler)
void wasm_config_set_engine(wasm_config_t *config, wasmer_engine_t engine);
void wasm_config_set_target(wasm_config_t *config, wasm_target_t *target);
void wasm_config_set_target(wasm_config_t *config, wasmer_target_t *target);
bool wasm_cpu_features_add(wasm_cpu_features_t *cpu_features, const wasm_name_t *feature);
bool wasmer_cpu_features_add(wasmer_cpu_features_t *cpu_features, const wasm_name_t *feature);
void wasm_cpu_features_delete(wasm_cpu_features_t *_cpu_features);
void wasmer_cpu_features_delete(wasmer_cpu_features_t *_cpu_features);
wasm_cpu_features_t *wasm_cpu_features_new(void);
wasmer_cpu_features_t *wasmer_cpu_features_new(void);
void wasm_module_name(const wasm_module_t *module, wasm_name_t *out);
bool wasmer_is_compiler_available(wasmer_compiler_t compiler);
bool wasm_module_set_name(wasm_module_t *module, const wasm_name_t *name);
bool wasmer_is_engine_available(wasmer_engine_t engine);
#if defined(WASMER_WASI_ENABLED)
const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern);
#endif
#if defined(WASMER_WASI_ENABLED)
const wasm_name_t *wasm_named_extern_name(const wasm_named_extern_t *named_extern);
#endif
#if defined(WASMER_WASI_ENABLED)
const wasm_extern_t *wasm_named_extern_unwrap(const wasm_named_extern_t *named_extern);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasm_named_extern_vec_copy(wasm_named_extern_vec_t *out_ptr,
const wasm_named_extern_vec_t *in_ptr);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasm_named_extern_vec_delete(wasm_named_extern_vec_t *ptr);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasm_named_extern_vec_new(wasm_named_extern_vec_t *out,
uintptr_t length,
wasm_named_extern_t *const *init);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasm_named_extern_vec_new_empty(wasm_named_extern_vec_t *out);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasm_named_extern_vec_new_uninitialized(wasm_named_extern_vec_t *out, uintptr_t length);
#endif
void wasm_target_delete(wasm_target_t *_target);
wasm_target_t *wasm_target_new(wasm_triple_t *triple, wasm_cpu_features_t *cpu_features);
void wasm_triple_delete(wasm_triple_t *_triple);
wasm_triple_t *wasm_triple_new(const wasm_name_t *triple);
wasm_triple_t *wasm_triple_new_from_host(void);
bool wasmer_is_headless(void);
int wasmer_last_error_length(void);
int wasmer_last_error_message(char *buffer, int length);
void wasmer_module_name(const wasm_module_t *module, wasm_name_t *out);
bool wasmer_module_set_name(wasm_module_t *module, const wasm_name_t *name);
#if defined(WASMER_WASI_ENABLED)
const wasm_name_t *wasmer_named_extern_module(const wasmer_named_extern_t *named_extern);
#endif
#if defined(WASMER_WASI_ENABLED)
const wasm_name_t *wasmer_named_extern_name(const wasmer_named_extern_t *named_extern);
#endif
#if defined(WASMER_WASI_ENABLED)
const wasm_extern_t *wasmer_named_extern_unwrap(const wasmer_named_extern_t *named_extern);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasmer_named_extern_vec_copy(wasmer_named_extern_vec_t *out_ptr,
const wasmer_named_extern_vec_t *in_ptr);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasmer_named_extern_vec_delete(wasmer_named_extern_vec_t *ptr);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasmer_named_extern_vec_new(wasmer_named_extern_vec_t *out,
uintptr_t length,
wasmer_named_extern_t *const *init);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasmer_named_extern_vec_new_empty(wasmer_named_extern_vec_t *out);
#endif
#if defined(WASMER_WASI_ENABLED)
void wasmer_named_extern_vec_new_uninitialized(wasmer_named_extern_vec_t *out, uintptr_t length);
#endif
void wasmer_target_delete(wasmer_target_t *_target);
wasmer_target_t *wasmer_target_new(wasmer_triple_t *triple, wasmer_cpu_features_t *cpu_features);
void wasmer_triple_delete(wasmer_triple_t *_triple);
wasmer_triple_t *wasmer_triple_new(const wasm_name_t *triple);
wasmer_triple_t *wasmer_triple_new_from_host(void);
wasmer_metering_points_t *wasmer_metering_get_remaining_points(const wasm_instance_t *instance);
wasmer_metering_t *wasmer_metering_new(uint64_t initial_limit);

View File

@@ -76,7 +76,10 @@ pub fn generate_header_file(
) -> String {
let mut c_statements = vec![];
c_statements.push(CStatement::LiteralConstant {
value: "#include <stdlib.h>\n\n".to_string(),
value: "#include <stdlib.h>\n#include <string.h>\n\n".to_string(),
});
c_statements.push(CStatement::LiteralConstant {
value: "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n".to_string(),
});
c_statements.push(CStatement::Declaration {
name: "module_bytes_len".to_string(),
@@ -285,11 +288,9 @@ pub fn generate_header_file(
value: HELPER_FUNCTIONS.to_string(),
});
let inner_c = generate_c(&c_statements);
c_statements.push(CStatement::LiteralConstant {
value: "\n#ifdef __cplusplus\n}\n#endif\n\n".to_string(),
});
// we wrap the inner C to work with C++ too
format!(
"#ifdef __cplusplus\nextern \"C\" {{\n#endif\n\n{}\n\n#ifdef __cplusplus\n}}\n#endif\n",
inner_c
)
generate_c(&c_statements)
}

View File

@@ -279,9 +279,13 @@ impl LinkCode {
command
};
// Add libraries required per platform.
// We need userenv, sockets (Ws2_32), and advapi32 to call a system call (for random numbers I think).
// We need userenv, sockets (Ws2_32), advapi32 for some system calls and bcrypt for random numbers.
#[cfg(windows)]
let command = command.arg("-luserenv").arg("-lWs2_32").arg("-ladvapi32");
let command = command
.arg("-luserenv")
.arg("-lWs2_32")
.arg("-ladvapi32")
.arg("-lbcrypt");
// On unix we need dlopen-related symbols, libmath for a few things, and pthreads.
#[cfg(not(windows))]
let command = command.arg("-ldl").arg("-lm").arg("-pthread");

View File

@@ -1,63 +1,42 @@
#ifdef __cplusplus
extern "C" {
#endif
#include "wasmer_wasm.h"
#include "wasm.h"
#include "my_wasm.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define own
// TODO: make this define templated so that the Rust code can toggle it on/off
#define WASI
#ifdef __cplusplus
}
#endif
void print_wasmer_error()
{
static void print_wasmer_error() {
int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char* error_str = (char*) malloc(error_len);
char *error_str = (char *)malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("%s\n", error_str);
free(error_str);
}
#ifdef WASI
int find_colon(char* string) {
int colon_location = 0;
for (int j = 0; j < strlen(string); ++j) {
if (string[j] == ':') {
colon_location = j;
break;
}
}
return colon_location;
}
void pass_mapdir_arg(wasi_config_t* wasi_config, char* mapdir) {
int colon_location = find_colon(mapdir);
static void pass_mapdir_arg(wasi_config_t *wasi_config, char *mapdir) {
int colon_location = strchr(mapdir, ':') - mapdir;
if (colon_location == 0) {
// error malformed argument
fprintf(stderr, "Expected mapdir argument of the form alias:directory\n");
exit(-1);
}
char *alias = (char *)malloc(colon_location + 1);
memcpy(alias, mapdir, colon_location);
alias[colon_location] = '\0';
int dir_len = strlen(mapdir) - colon_location;
char* alias = (char*)malloc(colon_location + 1);
char* dir = (char*)malloc(dir_len + 1);
int j = 0;
for (j = 0; j < colon_location; ++j) {
alias[j] = mapdir[j];
}
alias[j] = 0;
for (j = 0; j < dir_len; ++j) {
dir[j] = mapdir[j + colon_location + 1];
}
dir[j] = 0;
char *dir = (char *)malloc(dir_len + 1);
memcpy(dir, &mapdir[colon_location + 1], dir_len);
dir[dir_len] = '\0';
wasi_config_mapdir(wasi_config, alias, dir);
free(alias);
@@ -66,40 +45,41 @@ void pass_mapdir_arg(wasi_config_t* wasi_config, char* mapdir) {
// We try to parse out `--dir` and `--mapdir` ahead of time and process those
// specially. All other arguments are passed to the guest program.
void handle_arguments(wasi_config_t* wasi_config, int argc, char* argv[]) {
static void handle_arguments(wasi_config_t *wasi_config, int argc,
char *argv[]) {
for (int i = 1; i < argc; ++i) {
// We probably want special args like `--dir` and `--mapdir` to not be passed directly
// We probably want special args like `--dir` and `--mapdir` to not be
// passed directly
if (strcmp(argv[i], "--dir") == 0) {
// next arg is a preopen directory
if ((i + 1) < argc ) {
if ((i + 1) < argc) {
i++;
wasi_config_preopen_dir(wasi_config, argv[i]);
} else {
fprintf(stderr, "--dir expects a following argument specifying which directory to preopen\n");
fprintf(stderr, "--dir expects a following argument specifying which "
"directory to preopen\n");
exit(-1);
}
}
else if (strcmp(argv[i], "--mapdir") == 0) {
} else if (strcmp(argv[i], "--mapdir") == 0) {
// next arg is a mapdir
if ((i + 1) < argc ) {
if ((i + 1) < argc) {
i++;
pass_mapdir_arg(wasi_config, argv[i]);
} else {
fprintf(stderr, "--mapdir expects a following argument specifying which directory to preopen in the form alias:directory\n");
fprintf(stderr,
"--mapdir expects a following argument specifying which "
"directory to preopen in the form alias:directory\n");
exit(-1);
}
}
else if (strncmp(argv[i], "--dir=", strlen("--dir=")) == 0 ) {
} else if (strncmp(argv[i], "--dir=", strlen("--dir=")) == 0) {
// this arg is a preopen dir
char* dir = argv[i] + strlen("--dir=");
char *dir = argv[i] + strlen("--dir=");
wasi_config_preopen_dir(wasi_config, dir);
}
else if (strncmp(argv[i], "--mapdir=", strlen("--mapdir=")) == 0 ) {
} else if (strncmp(argv[i], "--mapdir=", strlen("--mapdir=")) == 0) {
// this arg is a mapdir
char* mapdir = argv[i] + strlen("--mapdir=");
char *mapdir = argv[i] + strlen("--mapdir=");
pass_mapdir_arg(wasi_config, mapdir);
}
else {
} else {
// guest argument
wasi_config_arg(wasi_config, argv[i]);
}
@@ -107,41 +87,42 @@ void handle_arguments(wasi_config_t* wasi_config, int argc, char* argv[]) {
}
#endif
int main(int argc, char* argv[]) {
wasm_config_t* config = wasm_config_new();
int main(int argc, char *argv[]) {
wasm_config_t *config = wasm_config_new();
wasm_config_set_engine(config, OBJECT_FILE);
wasm_engine_t* engine = wasm_engine_new_with_config(config);
wasm_store_t* store = wasm_store_new(engine);
wasm_module_t* module = wasmer_object_file_engine_new(store, argv[0]);
if (! module) {
wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine);
wasm_module_t *module = wasmer_object_file_engine_new(store, argv[0]);
if (!module) {
fprintf(stderr, "Failed to create module\n");
print_wasmer_error();
return -1;
}
// We have now finished the memory buffer book keeping and we have a valid Module.
#ifdef WASI
wasi_config_t* wasi_config = wasi_config_new(argv[0]);
// We have now finished the memory buffer book keeping and we have a valid
// Module.
#ifdef WASI
wasi_config_t *wasi_config = wasi_config_new(argv[0]);
handle_arguments(wasi_config, argc, argv);
wasi_env_t* wasi_env = wasi_env_new(wasi_config);
wasi_env_t *wasi_env = wasi_env_new(wasi_config);
if (!wasi_env) {
fprintf(stderr, "Error building WASI env!\n");
print_wasmer_error();
return 1;
}
#endif
#endif
wasm_importtype_vec_t import_types;
wasm_module_imports(module, &import_types);
wasm_extern_vec_t imports;
wasm_extern_vec_new_uninitialized(&imports, import_types.size);
wasm_importtype_vec_delete(&import_types);
#ifdef WASI
#ifdef WASI
bool get_imports_result = wasi_get_imports(store, module, wasi_env, &imports);
wasi_env_delete(wasi_env);
@@ -151,18 +132,18 @@ int main(int argc, char* argv[]) {
return 1;
}
#endif
wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL);
#endif
wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
fprintf(stderr, "Failed to create instance\n");
print_wasmer_error();
return -1;
}
#ifdef WASI
own wasm_func_t* start_function = wasi_get_start_function(instance);
#ifdef WASI
own wasm_func_t *start_function = wasi_get_start_function(instance);
if (!start_function) {
fprintf(stderr, "`_start` function not found\n");
print_wasmer_error();
@@ -171,15 +152,15 @@ int main(int argc, char* argv[]) {
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
own wasm_trap_t* trap = wasm_func_call(start_function, &args, &results);
own wasm_trap_t *trap = wasm_func_call(start_function, &args, &results);
if (trap) {
fprintf(stderr, "Trap is not NULL: TODO:\n");
return -1;
}
#endif
#endif
// TODO: handle non-WASI start (maybe with invoke?)
wasm_instance_delete(instance);
wasm_module_delete(module);
wasm_store_delete(store);

View File

@@ -15,19 +15,19 @@ edition = "2018"
wasmer-compiler = { path = "../compiler", version = "1.0.2", features = ["translator"], default-features = false }
wasmer-vm = { path = "../vm", version = "1.0.2" }
wasmer-types = { path = "../wasmer-types", version = "1.0.2", default-features = false, features = ["std"] }
cranelift-codegen = { version = "0.68", default-features = false, features = ["x86", "arm64"] }
cranelift-frontend = { version = "0.68", default-features = false }
cranelift-codegen = { version = "0.70", default-features = false, features = ["x86", "arm64"] }
cranelift-frontend = { version = "0.70", default-features = false }
tracing = "0.1"
hashbrown = { version = "0.9", optional = true }
rayon = "1.5"
serde = { version = "1.0", features = ["derive"] }
more-asserts = "0.2"
gimli = { version = "0.22", optional = true }
gimli = { version = "0.23", optional = true }
smallvec = "1.6"
[dev-dependencies]
target-lexicon = { version = "0.11", default-features = false }
cranelift-codegen = { version = "0.67", features = ["enable-serde", "all-arch"] }
cranelift-codegen = { version = "0.70", features = ["enable-serde", "all-arch"] }
lazy_static = "1.4"
[badges]

View File

@@ -20,15 +20,6 @@ pub(crate) struct RelocSink<'a> {
}
impl<'a> binemit::RelocSink for RelocSink<'a> {
fn reloc_block(
&mut self,
_offset: binemit::CodeOffset,
_reloc: binemit::Reloc,
_block_offset: binemit::CodeOffset,
) {
// This should use the `offsets` field of `ir::Function`.
panic!("block headers not yet implemented");
}
fn reloc_external(
&mut self,
offset: binemit::CodeOffset,

View File

@@ -21,14 +21,6 @@ pub mod binemit {
pub struct TrampolineRelocSink {}
impl binemit::RelocSink for TrampolineRelocSink {
fn reloc_block(
&mut self,
_offset: binemit::CodeOffset,
_reloc: binemit::Reloc,
_block_offset: binemit::CodeOffset,
) {
panic!("trampoline compilation should not produce block relocs");
}
fn reloc_external(
&mut self,
_offset: binemit::CodeOffset,

View File

@@ -1552,7 +1552,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// operands must match (hence the bitcast).
state.push1(builder.ins().bitselect(bitcast_c, bitcast_a, bitcast_b))
}
Operator::I8x16AnyTrue | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue => {
Operator::V128AnyTrue => {
let a = pop1_with_bitcast(state, type_of(op), builder);
let bool_result = builder.ins().vany_true(a);
state.push1(builder.ins().bint(I32, bool_result))
@@ -1757,6 +1757,52 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
}
Operator::I64x2Eq
| Operator::I64x2Ne
| Operator::I64x2AllTrue
| Operator::I64x2Bitmask
| Operator::I64x2WidenLowI32x4S
| Operator::I64x2WidenHighI32x4S
| Operator::I64x2WidenLowI32x4U
| Operator::I64x2WidenHighI32x4U
| Operator::I16x8ExtMulLowI8x16S
| Operator::I16x8ExtMulHighI8x16S
| Operator::I16x8ExtMulLowI8x16U
| Operator::I16x8ExtMulHighI8x16U
| Operator::I32x4ExtMulLowI16x8S
| Operator::I32x4ExtMulHighI16x8S
| Operator::I32x4ExtMulLowI16x8U
| Operator::I32x4ExtMulHighI16x8U
| Operator::I64x2ExtMulLowI32x4S
| Operator::I64x2ExtMulHighI32x4S
| Operator::I64x2ExtMulLowI32x4U
| Operator::I64x2ExtMulHighI32x4U
| Operator::V128Load8Lane { .. }
| Operator::V128Load16Lane { .. }
| Operator::V128Load32Lane { .. }
| Operator::V128Load64Lane { .. }
| Operator::V128Store8Lane { .. }
| Operator::V128Store16Lane { .. }
| Operator::V128Store32Lane { .. }
| Operator::V128Store64Lane { .. }
| Operator::I16x8Q15MulrSatS
| Operator::F32x4DemoteF64x2Zero
| Operator::F64x2PromoteLowF32x4
| Operator::F64x2ConvertLowI32x4S
| Operator::F64x2ConvertLowI32x4U
| Operator::I32x4TruncSatF64x2SZero
| Operator::I32x4TruncSatF64x2UZero => {
return Err(wasm_unsupported!("updated proposed simd operator {:?}", op));
}
Operator::Try { .. }
| Operator::Catch { .. }
| Operator::Throw { .. }
| Operator::Rethrow { .. }
| Operator::Unwind => {
return Err(wasm_unsupported!("proposed exception operator {:?}", op));
}
};
Ok(())
}
@@ -2395,7 +2441,6 @@ fn type_of(operator: &Operator) -> Type {
| Operator::I8x16GeU
| Operator::I8x16Neg
| Operator::I8x16Abs
| Operator::I8x16AnyTrue
| Operator::I8x16AllTrue
| Operator::I8x16Shl
| Operator::I8x16ShrS
@@ -2430,7 +2475,6 @@ fn type_of(operator: &Operator) -> Type {
| Operator::I16x8GeU
| Operator::I16x8Neg
| Operator::I16x8Abs
| Operator::I16x8AnyTrue
| Operator::I16x8AllTrue
| Operator::I16x8Shl
| Operator::I16x8ShrS
@@ -2465,7 +2509,6 @@ fn type_of(operator: &Operator) -> Type {
| Operator::I32x4GeU
| Operator::I32x4Neg
| Operator::I32x4Abs
| Operator::I32x4AnyTrue
| Operator::I32x4AllTrue
| Operator::I32x4Shl
| Operator::I32x4ShrS

View File

@@ -17,7 +17,7 @@ wasmer-vm = { path = "../vm", version = "1.0.2" }
wasmer-types = { path = "../wasmer-types", version = "1.0.2" }
target-lexicon = { version = "0.11", default-features = false }
smallvec = "1.6"
goblin = "0.2"
goblin = "0.3"
libc = { version = "^0.2", default-features = false }
byteorder = "1"
itertools = "0.9"

View File

@@ -6722,7 +6722,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let res = self.builder.build_not(v, "");
self.state.push1(res);
}
Operator::I8x16AnyTrue | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue => {
Operator::V128AnyTrue => {
// | Operator::I64x2AnyTrue
// Skip canonicalization, it never changes non-zero values to zero or vice versa.
let v = self.state.pop1()?.into_int_value();

View File

@@ -13,7 +13,7 @@ edition = "2018"
[dependencies]
wasmer-vm = { path = "../vm", version = "1.0.2" }
wasmer-types = { path = "../wasmer-types", version = "1.0.2", default-features = false }
wasmparser = { version = "0.65", optional = true, default-features = false }
wasmparser = { version = "0.74", optional = true, default-features = false }
target-lexicon = { version = "0.11", default-features = false }
enumset = "1.0"
hashbrown = { version = "0.9", optional = true }

View File

@@ -78,6 +78,7 @@ pub trait Compiler: Send {
module_linking: features.module_linking,
multi_memory: features.multi_memory,
memory64: features.memory64,
exceptions: features.exceptions,
deterministic_only: false,
};
validator.wasm_features(wasm_features);

View File

@@ -81,11 +81,11 @@ pub fn translate_module<'data>(
environ.reserve_passive_data(count)?;
}
Payload::ModuleSection(_)
| Payload::InstanceSection(_)
Payload::InstanceSection(_)
| Payload::AliasSection(_)
| Payload::ModuleCodeSectionStart { .. }
| Payload::ModuleCodeSectionEntry { .. } => {
| Payload::EventSection(_)
| Payload::ModuleSectionStart { .. }
| Payload::ModuleSectionEntry { .. } => {
unimplemented!("module linking not implemented yet")
}

View File

@@ -105,7 +105,9 @@ pub fn parse_import_section<'data>(
field_name.unwrap_or_default(),
)?;
}
ImportSectionEntryType::Module(_sig) | ImportSectionEntryType::Instance(_sig) => {
ImportSectionEntryType::Module(_)
| ImportSectionEntryType::Instance(_)
| ImportSectionEntryType::Event(_) => {
unimplemented!("module linking not implemented yet")
}
ImportSectionEntryType::Memory(WPMemoryType::M32 {
@@ -292,7 +294,10 @@ pub fn parse_export_section<'data>(
ExternalKind::Global => {
environ.declare_global_export(GlobalIndex::new(index), field)?
}
ExternalKind::Type | ExternalKind::Module | ExternalKind::Instance => {
ExternalKind::Type
| ExternalKind::Module
| ExternalKind::Instance
| ExternalKind::Event => {
unimplemented!("module linking not implemented yet")
}
}

View File

@@ -293,7 +293,7 @@ impl NativeArtifact {
Triple::host().to_string(),
);
let linker: &'static str = engine_inner.linker().into();
let linker = engine_inner.linker().executable();
let output = Command::new(linker)
.arg(&filepath)
.arg("-o")

View File

@@ -13,8 +13,6 @@ use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
use wasmer_types::Features;
use wasmer_types::FunctionType;
use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex};
#[cfg(feature = "compiler")]
use which::which;
/// A WebAssembly `Native` Engine.
#[derive(Clone)]
@@ -29,22 +27,8 @@ impl NativeEngine {
/// Create a new `NativeEngine` with the given config
#[cfg(feature = "compiler")]
pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
let host_target = Triple::host();
let is_cross_compiling = target.triple() != &host_target;
let linker = if is_cross_compiling {
which(Into::<&'static str>::into(Linker::Clang10))
.map(|_| Linker::Clang10)
.or_else(|_| {
which(Into::<&'static str>::into(Linker::Clang))
.map(|_| Linker::Clang)
})
.expect("Nor `clang-10` or `clang` has been found, at least one of them is required for the `NativeEngine`")
} else {
which(Into::<&'static str>::into(Linker::Gcc))
.map(|_| Linker::Gcc)
.expect("`gcc` has not been found, it is required for the `NativeEngine`")
};
let is_cross_compiling = *target.triple() != Triple::host();
let linker = Linker::find_linker(is_cross_compiling);
Self {
inner: Arc::new(Mutex::new(NativeEngineInner {
@@ -193,15 +177,40 @@ impl Engine for NativeEngine {
#[derive(Clone, Copy)]
pub(crate) enum Linker {
None,
Clang11,
Clang10,
Clang,
Gcc,
}
impl Into<&'static str> for Linker {
fn into(self) -> &'static str {
impl Linker {
#[cfg(feature = "compiler")]
fn find_linker(is_cross_compiling: bool) -> Self {
let (possibilities, requirements): (&[_], _) = if is_cross_compiling {
(
&[Linker::Clang11, Linker::Clang10, Linker::Clang],
"at least one of `clang-11`, `clang-10`, or `clang`",
)
} else {
(&[Linker::Gcc], "`gcc`")
};
*possibilities
.iter()
.filter(|linker| which::which(linker.executable()).is_ok())
.next()
.unwrap_or_else(|| {
panic!(
"Need {} installed in order to use `NativeEngine` when {}cross-compiling",
requirements,
if is_cross_compiling { "" } else { "not " }
)
})
}
pub(crate) fn executable(self) -> &'static str {
match self {
Self::None => "",
Self::Clang11 => "clang-11",
Self::Clang10 => "clang-10",
Self::Clang => "clang",
Self::Gcc => "gcc",

View File

@@ -25,10 +25,6 @@ Target: x86_64-apple-darwin
Now lets create a program to link with this object file.
```C
#ifdef __cplusplus
extern "C" {
#endif
#include "wasmer_wasm.h"
#include "wasm.h"
#include "my_wasm.h"
@@ -38,17 +34,14 @@ extern "C" {
#define own
#ifdef __cplusplus
}
#endif
void print_wasmer_error()
static void print_wasmer_error()
{
int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char* error_str = (char*) malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("Error str: `%s`\n", error_str);
free(error_str);
}
int main() {
@@ -59,7 +52,7 @@ int main() {
wasm_store_t* store = wasm_store_new(engine);
wasm_module_t* module = wasmer_object_file_engine_new(store, "qjs.wasm");
if (! module) {
if (!module) {
printf("Failed to create module\n");
print_wasmer_error();
return -1;

View File

@@ -16,5 +16,5 @@ wasmer-compiler = { path = "../compiler", version = "1.0.2", default-features =
"std",
"translator"
] }
object = { version = "0.22", default-features = false, features = ["write"] }
object = { version = "0.23", default-features = false, features = ["write"] }
thiserror = "1.0"

View File

@@ -13,7 +13,7 @@ edition = "2018"
[dependencies]
# We use `cranelift-entity` here because it's a lightweight dependency and it contains
# some useful data structures
cranelift-entity = "0.68"
cranelift-entity = "0.70"
serde = { version = "1.0", features = ["derive"], optional = true, default-features = false }
thiserror = "1.0"

View File

@@ -26,6 +26,8 @@ pub struct Features {
pub multi_memory: bool,
/// 64-bit Memory proposal should be enabled
pub memory64: bool,
/// Wasm exceptions proposal should be enabled
pub exceptions: bool,
}
impl Features {
@@ -43,6 +45,7 @@ impl Features {
module_linking: false,
multi_memory: false,
memory64: false,
exceptions: false,
}
}
@@ -249,6 +252,7 @@ mod test_features {
module_linking: false,
multi_memory: false,
memory64: false,
exceptions: false,
}
);
}

View File

@@ -34,6 +34,16 @@ cranelift::spec::simd::simd_i8x16_sat_arith on aarch64
cranelift::spec::simd::simd_lane on aarch64
cranelift::spec::skip_stack_guard_page on aarch64
# SIMD changes
# due to breaking changes in the SIMD proposal, we have to disable these spec tests
# note we've not pulled in the updated spec tests yet, so expect more breakage
cranelift::spec::simd::simd_boolean
cranelift::spec::simd::simd_lane
llvm::spec::simd::simd_boolean
llvm::spec::simd::simd_lane
# Frontends
## WASI

View File

@@ -50,7 +50,11 @@ impl LinkCode {
)
.arg(&self.libwasmer_path.canonicalize()?);
#[cfg(windows)]
let command = command.arg("-luserenv").arg("-lWs2_32").arg("-ladvapi32");
let command = command
.arg("-luserenv")
.arg("-lWs2_32")
.arg("-ladvapi32")
.arg("-lbcrypt");
#[cfg(not(windows))]
let command = command.arg("-ldl").arg("-lm").arg("-pthread");
let output = command.arg("-o").arg(&self.output_path).output()?;

View File

@@ -1,7 +1,3 @@
#ifdef __cplusplus
extern "C" {
#endif
#include "wasmer_wasm.h"
#include "wasm.h"
#include "my_wasm.h"
@@ -11,43 +7,42 @@ extern "C" {
#define own
#ifdef __cplusplus
}
#endif
void print_wasmer_error()
{
static void print_wasmer_error() {
int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char* error_str = (char*) malloc(error_len);
char *error_str = (char *)malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("Error str: `%s`\n", error_str);
free(error_str);
}
int main() {
printf("Initializing...\n");
wasm_config_t* config = wasm_config_new();
wasm_config_t *config = wasm_config_new();
wasm_config_set_engine(config, OBJECT_FILE);
wasm_engine_t* engine = wasm_engine_new_with_config(config);
wasm_store_t* store = wasm_store_new(engine);
wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine);
wasm_module_t* module = wasmer_object_file_engine_new(store, "qjs.wasm");
wasm_module_t *module = wasmer_object_file_engine_new(store, "qjs.wasm");
if (!module) {
printf("Failed to create module\n");
print_wasmer_error();
return -1;
}
// We have now finished the memory buffer book keeping and we have a valid Module.
// In this example we're passing some JavaScript source code as a command line argument
// to a WASI module that can evaluate JavaScript.
wasi_config_t* wasi_config = wasi_config_new("constant_value_here");
const char* js_string = "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));";
// We have now finished the memory buffer book keeping and we have a valid
// Module.
// In this example we're passing some JavaScript source code as a command line
// argument to a WASI module that can evaluate JavaScript.
wasi_config_t *wasi_config = wasi_config_new("constant_value_here");
const char *js_string =
"function greet(name) { return JSON.stringify('Hello, ' + name); }; "
"print(greet('World'));";
wasi_config_arg(wasi_config, "--eval");
wasi_config_arg(wasi_config, js_string);
wasi_env_t* wasi_env = wasi_env_new(wasi_config);
wasi_env_t *wasi_env = wasi_env_new(wasi_config);
if (!wasi_env) {
printf("> Error building WASI env!\n");
@@ -61,7 +56,7 @@ int main() {
wasm_extern_vec_t imports;
wasm_extern_vec_new_uninitialized(&imports, import_types.size);
wasm_importtype_vec_delete(&import_types);
bool get_imports_result = wasi_get_imports(store, module, wasi_env, &imports);
wasi_env_delete(wasi_env);
@@ -71,7 +66,7 @@ int main() {
return 1;
}
wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL);
wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("Failed to create instance\n");
@@ -81,7 +76,7 @@ int main() {
wasi_env_set_instance(wasi_env, instance);
// WASI is now set up.
own wasm_func_t* start_function = wasi_get_start_function(instance);
own wasm_func_t *start_function = wasi_get_start_function(instance);
if (!start_function) {
fprintf(stderr, "`_start` function not found\n");
print_wasmer_error();
@@ -92,7 +87,7 @@ int main() {
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
own wasm_trap_t* trap = wasm_func_call(start_function, &args, &results);
own wasm_trap_t *trap = wasm_func_call(start_function, &args, &results);
if (trap) {
fprintf(stderr, "Trap is not NULL: TODO:\n");
return -1;

View File

@@ -74,6 +74,7 @@ impl Engine for DummyEngine {
module_linking: features.module_linking,
multi_memory: features.multi_memory,
memory64: features.memory64,
exceptions: features.exceptions,
deterministic_only: false,
};
validator.wasm_features(wasm_features);

View File

@@ -3,6 +3,7 @@ name = "test-generator"
version = "0.1.0"
edition = "2018"
publish = false
license = "Apache-2.0 WITH LLVM-exception"
[dependencies]
anyhow = "1.0"

View File

@@ -351,7 +351,7 @@ impl Wast {
let instance = self
.instances
.get(module_name)
.ok_or_else(|| anyhow!("no module named `{}`", module_name))?;
.ok_or_else(|| anyhow!("constant expression required"))?;
imports.register(module_name, instance.exports.clone());
}
@@ -421,6 +421,11 @@ impl Wast {
// `elem.wast` and `proposals/bulk-memory-operations/elem.wast` disagree
// on the expected error message for the same error.
|| (expected.contains("out of bounds") && actual.contains("does not fit"))
// handle `unknown global $NUM` error messages that wasmparser doesn't return yet
|| (expected.contains("unknown global") && actual.contains("unknown global"))
// handle `unknown memory $NUM` error messages that wasmparser doesn't return yet
|| (expected.contains("unknown memory") && actual.contains("unknown memory"))
|| (expected.contains("unknown memory") && actual.contains("Data segment extends past end of the data section"))
}
// Checks if the `assert_trap` message matches the expected one

View File

@@ -191,6 +191,13 @@
(assert_return (invoke "32_good4" (i32.const 65508)) (i32.const 0))
(assert_trap (invoke "32_good5" (i32.const 65508)) "out of bounds memory access")
(assert_trap (invoke "8u_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "8s_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "16u_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "16s_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "8u_bad" (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "8s_bad" (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "16u_bad" (i32.const 0)) "out of bounds memory access")
@@ -478,6 +485,14 @@
(assert_return (invoke "64_good4" (i32.const 65504)) (i64.const 0))
(assert_trap (invoke "64_good5" (i32.const 65504)) "out of bounds memory access")
(assert_trap (invoke "8u_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "8s_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "16u_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "16s_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "32u_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "32s_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "64_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "8u_bad" (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "8s_bad" (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "16u_bad" (i32.const 0)) "out of bounds memory access")
@@ -538,6 +553,9 @@
(assert_return (invoke "32_good4" (i32.const 65525)) (f32.const 0.0))
(assert_trap (invoke "32_good5" (i32.const 65525)) "out of bounds memory access")
(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "32_bad" (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "32_bad" (i32.const 1)) "out of bounds memory access")
@@ -585,5 +603,8 @@
(assert_return (invoke "64_good4" (i32.const 65511)) (f64.const 0.0))
(assert_trap (invoke "64_good5" (i32.const 65511)) "out of bounds memory access")
(assert_trap (invoke "64_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "64_good3" (i32.const -1)) "out of bounds memory access")
(assert_trap (invoke "64_bad" (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "64_bad" (i32.const 1)) "out of bounds memory access")

View File

@@ -852,7 +852,7 @@
"\41\00" ;; i32.const 0
"\41\03" ;; i32.const 3
"\36" ;; i32.store
"\03" ;; alignment 2
"\02" ;; alignment 2
"\82\80\80\80\10" ;; offset 2 with unused bits set
"\0b" ;; end
)
@@ -961,3 +961,41 @@
)
"integer too large"
)
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01" ;; type section
"\60\00\00" ;; empty function type
"\03\02\01" ;; function section
"\00" ;; function 0, type 0
"\0a\1b\01\19" ;; code section
"\00" ;; no locals
"\00" ;; unreachable
"\fc\80\00" ;; i32_trunc_sat_f32_s with 2 bytes
"\00" ;; unreachable
"\fc\81\80\00" ;; i32_trunc_sat_f32_u with 3 bytes
"\00" ;; unreachable
"\fc\86\80\80\00" ;; i64_trunc_sat_f64_s with 4 bytes
"\00" ;; unreachable
"\fc\87\80\80\80\00" ;; i64_trunc_sat_f64_u with 5 bytes
"\00" ;; unreachable
"\0b" ;; end
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01" ;; type section
"\60\00\00" ;; empty function type
"\03\02\01" ;; function section
"\00" ;; function 0, type 0
"\0a\0d\01\0b" ;; code section
"\00" ;; no locals
"\00" ;; unreachable
"\fc\87\80\80\80\80\00" ;; i64_trunc_sat_f64_u with 6 bytes
"\00" ;; unreachable
"\0b" ;; end
)
"integer representation too long"
)

View File

@@ -44,6 +44,27 @@
(assert_malformed (module binary "\00asm\00\00\01\00") "unknown binary version")
(assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version")
;; Invalid section id.
(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0c\00") "malformed section id")
(assert_malformed (module binary "\00asm" "\01\00\00\00" "\7f\00") "malformed section id")
(assert_malformed (module binary "\00asm" "\01\00\00\00" "\80\00\01\00") "malformed section id")
(assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\00\01\00") "malformed section id")
(assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\00\01\00") "malformed section id")
;; Type section with signed LEB128 encoded type
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01" ;; Type section id
"\05" ;; Type section length
"\01" ;; Types vector length
"\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding
"\00\00"
)
"integer representation too long"
)
;; call_indirect reserved byte equal to zero.
(assert_malformed
@@ -329,7 +350,24 @@
"zero flag expected"
)
;; No more than 2^32 locals.
;; Local number is unsigned 32 bit
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\0a\0c\01" ;; Code section
;; function 0
"\0a\02"
"\80\80\80\80\10\7f" ;; 0x100000000 i32
"\02\7e" ;; 0x00000002 i64
"\0b" ;; end
)
"integer too large"
)
;; No more than 2^32-1 locals.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
@@ -346,6 +384,24 @@
"too many locals"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\06\01\60\02\7f\7f\00" ;; Type section: (param i32 i32)
"\03\02\01\00" ;; Function section
"\0a\1c\01" ;; Code section
;; function 0
"\1a\04"
"\80\80\80\80\04\7f" ;; 0x40000000 i32
"\80\80\80\80\04\7e" ;; 0x40000000 i64
"\80\80\80\80\04\7d" ;; 0x40000000 f32
"\80\80\80\80\04\7c" ;; 0x40000000 f64
"\0b" ;; end
)
"too many locals"
)
;; Local count can be 0.
(module binary
"\00asm" "\01\00\00\00"
@@ -450,6 +506,71 @@
"\02\01\00" ;; import count can be zero
)
;; Malformed import kind
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\02\04\01" ;; import section with single entry
"\00" ;; string length 0
"\00" ;; string length 0
"\04" ;; malformed import kind
)
"malformed import kind"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\02\05\01" ;; import section with single entry
"\00" ;; string length 0
"\00" ;; string length 0
"\04" ;; malformed import kind
"\00" ;; dummy byte
)
"malformed import kind"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\02\04\01" ;; import section with single entry
"\00" ;; string length 0
"\00" ;; string length 0
"\05" ;; malformed import kind
)
"malformed import kind"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\02\05\01" ;; import section with single entry
"\00" ;; string length 0
"\00" ;; string length 0
"\05" ;; malformed import kind
"\00" ;; dummy byte
)
"malformed import kind"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\02\04\01" ;; import section with single entry
"\00" ;; string length 0
"\00" ;; string length 0
"\80" ;; malformed import kind
)
"malformed import kind"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\02\05\01" ;; import section with single entry
"\00" ;; string length 0
"\00" ;; string length 0
"\80" ;; malformed import kind
"\00" ;; dummy byte
)
"malformed import kind"
)
;; 2 import declared, 1 given
(assert_malformed
(module binary
@@ -510,6 +631,37 @@
"unexpected end of section or function"
)
;; Malformed table limits flag
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\03\01" ;; table section with one entry
"\70" ;; anyfunc
"\02" ;; malformed table limits flag
)
"integer too large"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\04\01" ;; table section with one entry
"\70" ;; anyfunc
"\02" ;; malformed table limits flag
"\00" ;; dummy byte
)
"integer too large"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\06\01" ;; table section with one entry
"\70" ;; anyfunc
"\81\00" ;; malformed table limits flag as LEB128
"\00\00" ;; dummy bytes
)
"integer too large"
)
;; Memory count can be zero
(module binary
"\00asm" "\01\00\00\00"
@@ -526,6 +678,43 @@
"unexpected end of section or function"
)
;; Malformed memory limits flag
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\02\01" ;; memory section with one entry
"\02" ;; malformed memory limits flag
)
"integer too large"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\03\01" ;; memory section with one entry
"\02" ;; malformed memory limits flag
"\00" ;; dummy byte
)
"integer too large"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\05\01" ;; memory section with one entry
"\81\00" ;; malformed memory limits flag as LEB128
"\00\00" ;; dummy bytes
)
"integer representation too long"
)
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\05\05\01" ;; memory section with one entry
"\81\01" ;; malformed memory limits flag as LEB128
"\00\00" ;; dummy bytes
)
"integer representation too long"
)
;; Global count can be zero
(module binary
"\00asm" "\01\00\00\00"
@@ -633,8 +822,23 @@
"\09\07\02" ;; elem with inconsistent segment count (2 declared, 1 given)
"\00\41\00\0b\01\00" ;; elem 0
;; "\00\41\00\0b\01\00" ;; elem 1 (missed)
"\0a\04\01" ;; code section
"\02\00\0b" ;; function body
)
"unexpected end"
)
;; 2 elem segment declared, 1.5 given
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01" ;; type section
"\60\00\00" ;; type 0
"\03\02\01\00" ;; func section
"\04\04\01" ;; table section
"\70\00\01" ;; table 0
"\09\07\02" ;; elem with inconsistent segment count (2 declared, 1 given)
"\00\41\00\0b\01\00" ;; elem 0
"\00\41\00" ;; elem 1 (partial)
;; "\0b\01\00" ;; elem 1 (missing part)
)
"unexpected end"
)
@@ -736,28 +940,6 @@
"\0b\0b\0b" ;; end
)
;; 2 br_table target declared, 1 given
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01" ;; type section
"\60\00\00" ;; type 0
"\03\02\01\00" ;; func section
"\0a\12\01" ;; code section
"\10\00" ;; func 0
"\02\40" ;; block 0
"\41\01" ;; condition of if 0
"\04\40" ;; if 0
"\41\01" ;; index of br_table element
"\0e\02" ;; br_table with inconsistent target count (2 declared, 1 given)
"\00" ;; break depth 0
;; "\01" ;; break depth 1 (missed)
"\02" ;; break depth for default
"\0b\0b\0b" ;; end
)
"unexpected end of section or function"
)
;; 1 br_table target declared, 2 given
(assert_malformed
(module binary

View File

@@ -1464,6 +1464,16 @@
))
"type mismatch"
)
(assert_invalid
(module (func
(block (result i32)
(block (result i64)
(br_table 0 1 (i32.const 0) (i32.const 0))
)
)
))
"type mismatch"
)
(assert_invalid
(module (func $type-index-void-vs-i32
@@ -1552,6 +1562,31 @@
"type mismatch"
)
(assert_invalid
(module
(func (param i32) (result i32)
(loop (result i32)
(block (result i32)
(br_table 0 1 (i32.const 1) (local.get 0))
)
)
)
)
"type mismatch"
)
(assert_invalid
(module
(func (param i32) (result i32)
(block (result i32)
(loop (result i32)
(br_table 0 1 (i32.const 1) (local.get 0))
)
)
)
)
"type mismatch"
)
(assert_invalid
(module (func $unbound-label

View File

@@ -154,6 +154,13 @@
(module (func (f64.const 0123456789.0123456789e019) drop))
(module (func (f64.const 0123456789.0123456789e+019) drop))
(module (func (f64.const 0123456789.0123456789e-019) drop))
(module (func (f64.const 0_1_2_3_4_5_6_7_8_9) drop))
(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.) drop))
(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.0_1_2_3_4_5_6_7_8_9) drop))
(module (func (f64.const 0_1_2_3_4_5_6_7_8_9e+0_1_9) drop))
(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.e+0_1_9) drop))
(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.0_1_2_3_4_5_6_7_8_9e0_1_9) drop))
(module (func (f64.const 0x0123456789ABCDEFabcdef) drop))
(module (func (f64.const 0x0123456789ABCDEFabcdefp019) drop))
(module (func (f64.const 0x0123456789ABCDEFabcdefp+019) drop))
@@ -166,6 +173,14 @@
(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp019) drop))
(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp+019) drop))
(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp-019) drop))
(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f) drop))
(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.) drop))
(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f) drop))
(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_fp0_1_9) drop))
(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.p0_1_9) drop))
(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_fp0_1_9) drop))
(assert_malformed
(module quote "(func (f64.const) drop)")
"unexpected token"

View File

@@ -120,6 +120,8 @@
(assert_return (invoke "i32.trunc_f64_s" (f64.const -2.0)) (i32.const -2))
(assert_return (invoke "i32.trunc_f64_s" (f64.const 2147483647.0)) (i32.const 2147483647))
(assert_return (invoke "i32.trunc_f64_s" (f64.const -2147483648.0)) (i32.const -2147483648))
(assert_return (invoke "i32.trunc_f64_s" (f64.const -2147483648.9)) (i32.const -2147483648))
(assert_return (invoke "i32.trunc_f64_s" (f64.const 2147483647.9)) (i32.const 2147483647))
(assert_trap (invoke "i32.trunc_f64_s" (f64.const 2147483648.0)) "integer overflow")
(assert_trap (invoke "i32.trunc_f64_s" (f64.const -2147483649.0)) "integer overflow")
(assert_trap (invoke "i32.trunc_f64_s" (f64.const inf)) "integer overflow")
@@ -143,6 +145,8 @@
(assert_return (invoke "i32.trunc_f64_u" (f64.const -0x1.ccccccccccccdp-1)) (i32.const 0))
(assert_return (invoke "i32.trunc_f64_u" (f64.const -0x1.fffffffffffffp-1)) (i32.const 0))
(assert_return (invoke "i32.trunc_f64_u" (f64.const 1e8)) (i32.const 100000000))
(assert_return (invoke "i32.trunc_f64_u" (f64.const -0.9)) (i32.const 0))
(assert_return (invoke "i32.trunc_f64_u" (f64.const 4294967295.9)) (i32.const 4294967295))
(assert_trap (invoke "i32.trunc_f64_u" (f64.const 4294967296.0)) "integer overflow")
(assert_trap (invoke "i32.trunc_f64_u" (f64.const -1.0)) "integer overflow")
(assert_trap (invoke "i32.trunc_f64_u" (f64.const 1e16)) "integer overflow")

View File

@@ -286,6 +286,72 @@
"unknown memory"
)
;; Data segment with memory index 1 (only memory 0 available)
(assert_invalid
(module binary
"\00asm" "\01\00\00\00"
"\05\03\01" ;; memory section
"\00\00" ;; memory 0
"\0b\06\01" ;; data section
"\01\41\00\0b" ;; data segment 0 for memory 1
"\00" ;; empty vec(byte)
)
"unknown memory 1"
)
;; Data segment with memory index 1 (no memory section)
(assert_invalid
(module binary
"\00asm" "\01\00\00\00"
"\0b\06\01" ;; data section
"\01\41\00\0b" ;; data segment 0 for memory 1
"\00" ;; empty vec(byte)
)
"unknown memory 1"
)
;; TODO: uncomment these tests:
;; wasmparser parses these but should not, we should fix it upstream if we get the chance.
;;
;; ;; Data segment with memory index 1 and vec(byte) as above,
;; ;; only memory 0 available.
;; (assert_invalid
;; (module binary
;; "\00asm" "\01\00\00\00"
;; "\05\03\01" ;; memory section
;; "\00\00" ;; memory 0
;; "\0b\44\01" ;; data section
;; "\01" ;; memory index
;; "\41\00\0b" ;; offset constant expression
;; "\3e" ;; vec(byte) length
;; "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f"
;; "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f"
;; "\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f"
;; "\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d"
;; )
;; "unknown memory 1"
;; )
;;
;; ;; Data segment with memory index 1 and specially crafted vec(byte) after.
;; ;; This is to detect incorrect validation where memory index is interpreted
;; ;; as a flag followed by "\41" interpreted as the size of vec(byte)
;; ;; with the expected number of bytes following.
;; (assert_invalid
;; (module binary
;; "\00asm" "\01\00\00\00"
;; "\0b\44\01" ;; data section
;; "\01" ;; memory index
;; "\41\00\0b" ;; offset constant expression
;; "\3e" ;; vec(byte) length
;; "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f"
;; "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f"
;; "\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f"
;; "\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d"
;; )
;; "unknown memory 1"
;; )
;; Invalid offsets
(assert_invalid
@@ -296,6 +362,40 @@
"type mismatch"
)
(assert_invalid
(module
(memory 1)
(data (offset (;empty instruction sequence;)))
)
"type mismatch"
)
(assert_invalid
(module
(memory 1)
(data (offset (i32.const 0) (i32.const 0)))
)
"type mismatch"
)
(assert_invalid
(module
(global (import "test" "global-i32") i32)
(memory 1)
(data (offset (global.get 0) (global.get 0)))
)
"type mismatch"
)
(assert_invalid
(module
(global (import "test" "global-i32") i32)
(memory 1)
(data (offset (global.get 0) (i32.const 0)))
)
"type mismatch"
)
(assert_invalid
(module
(memory 1)
@@ -333,3 +433,29 @@
;; (module (memory 1) (data (global.get $g)) (global $g (mut i32) (i32.const 0)))
;; "constant expression required"
;; )
(assert_invalid
(module
(memory 1)
(data (global.get 0))
)
"unknown global 0"
)
(assert_invalid
(module
(global (import "test" "global-i32") i32)
(memory 1)
(data (global.get 1))
)
"unknown global 1"
)
(assert_invalid
(module
(global (import "test" "global-mut-i32") (mut i32))
(memory 1)
(data (global.get 0))
)
"constant expression required"
)

View File

@@ -262,6 +262,41 @@
"type mismatch"
)
(assert_invalid
(module
(table 1 funcref)
(elem (offset (;empty instruction sequence;)))
)
"type mismatch"
)
(assert_invalid
(module
(table 1 funcref)
(elem (offset (i32.const 0) (i32.const 0)))
)
"type mismatch"
)
(assert_invalid
(module
(global (import "test" "global-i32") i32)
(table 1 funcref)
(elem (offset (global.get 0) (global.get 0)))
)
"type mismatch"
)
(assert_invalid
(module
(global (import "test" "global-i32") i32)
(table 1 funcref)
(elem (offset (global.get 0) (i32.const 0)))
)
"type mismatch"
)
(assert_invalid
(module
(table 1 funcref)
@@ -300,6 +335,32 @@
;; "constant expression required"
;; )
(assert_invalid
(module
(table 1 funcref)
(elem (global.get 0))
)
"unknown global 0"
)
(assert_invalid
(module
(global (import "test" "global-i32") i32)
(table 1 funcref)
(elem (global.get 1))
)
"unknown global 1"
)
(assert_invalid
(module
(global (import "test" "global-mut-i32") (mut i32))
(table 1 funcref)
(elem (global.get 0))
)
"constant expression required"
)
;; Two elements target the same slot
(module

View File

@@ -25,10 +25,18 @@
(module $Other1)
(assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43))
(assert_invalid
(module (export "a" (func 0)))
"unknown function"
)
(assert_invalid
(module (func) (export "a" (func 1)))
"unknown function"
)
(assert_invalid
(module (import "spectest" "print_i32" (func (param i32))) (export "a" (func 1)))
"unknown function"
)
(assert_invalid
(module (func) (export "a" (func 0)) (export "a" (func 0)))
"duplicate export name"
@@ -74,10 +82,18 @@
(module $Other2)
(assert_return (get $Global "e") (i32.const 42))
(assert_invalid
(module (export "a" (global 0)))
"unknown global"
)
(assert_invalid
(module (global i32 (i32.const 0)) (export "a" (global 1)))
"unknown global"
)
(assert_invalid
(module (import "spectest" "global_i32" (global i32)) (export "a" (global 1)))
"unknown global"
)
(assert_invalid
(module (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 0)))
"duplicate export name"
@@ -122,10 +138,18 @@
(; TODO: access table ;)
(assert_invalid
(module (export "a" (table 0)))
"unknown table"
)
(assert_invalid
(module (table 0 funcref) (export "a" (table 1)))
"unknown table"
)
(assert_invalid
(module (import "spectest" "table" (table 10 20 funcref)) (export "a" (table 1)))
"unknown table"
)
(assert_invalid
(module (table 0 funcref) (export "a" (table 0)) (export "a" (table 0)))
"duplicate export name"
@@ -171,10 +195,18 @@
(; TODO: access memory ;)
(assert_invalid
(module (export "a" (memory 0)))
"unknown memory"
)
(assert_invalid
(module (memory 0) (export "a" (memory 1)))
"unknown memory"
)
(assert_invalid
(module (import "spectest" "memory" (memory 1 2)) (export "a" (memory 1)))
"unknown memory"
)
(assert_invalid
(module (memory 0) (export "a" (memory 0)) (export "a" (memory 0)))
"duplicate export name"

View File

@@ -444,6 +444,46 @@
"unknown type"
)
(assert_malformed
(module quote
"(func $f (result f64) (f64.const 0))" ;; adds implicit type definition
"(func $g (param i32))" ;; reuses explicit type definition
"(func $h (result f64) (f64.const 1))" ;; reuses implicit type definition
"(type $t (func (param i32)))"
"(func (type 2) (param i32))" ;; does not exist
)
"unknown type"
)
(module
(type $proc (func (result i32)))
(type $sig (func (param i32) (result i32)))
(func (export "f") (type $sig)
(local $var i32)
(local.get $var)
)
(func $g (type $sig)
(local $var i32)
(local.get $var)
)
(func (export "g") (type $sig)
(call $g (local.get 0))
)
(func (export "p") (type $proc)
(local $var i32)
(local.set 0 (i32.const 42))
(local.get $var)
)
)
(assert_return (invoke "f" (i32.const 42)) (i32.const 0))
(assert_return (invoke "g" (i32.const 42)) (i32.const 0))
(assert_return (invoke "p") (i32.const 42))
(module
(type $sig (func))

View File

@@ -244,6 +244,11 @@
"global is immutable"
)
(assert_invalid
(module (import "spectest" "global_i32" (global i32)) (func (global.set 0 (i32.const 1))))
"global is immutable"
)
;; mutable globals can be exported
(module (global (mut f32) (f32.const 0)) (export "a" (global 0)))
(module (global (export "a") (mut f32) (f32.const 0)))
@@ -268,6 +273,11 @@
"constant expression required"
)
(assert_invalid
(module (global i32 (i32.ctz (i32.const 0))))
"constant expression required"
)
(assert_invalid
(module (global i32 (nop)))
"constant expression required"
@@ -288,6 +298,16 @@
"type mismatch"
)
(assert_invalid
(module (global (import "test" "global-i32") i32) (global i32 (global.get 0) (global.get 0)))
"type mismatch"
)
(assert_invalid
(module (global (import "test" "global-i32") i32) (global i32 (i32.const 0) (global.get 0)))
"type mismatch"
)
(assert_invalid
(module (global i32 (global.get 0)))
"unknown global"
@@ -298,6 +318,16 @@
"unknown global"
)
(assert_invalid
(module (global (import "test" "global-i32") i32) (global i32 (global.get 2)))
"unknown global"
)
(assert_invalid
(module (global (import "test" "global-mut-i32") (mut i32)) (global i32 (global.get 0)))
"constant expression required"
)
(module
(import "spectest" "global_i32" (global i32))
)
@@ -356,6 +386,68 @@
"malformed mutability"
)
;; global.get with invalid index
(assert_invalid
(module (func (result i32) (global.get 0)))
"unknown global"
)
(assert_invalid
(module
(global i32 (i32.const 0))
(func (result i32) (global.get 1))
)
"unknown global"
)
(assert_invalid
(module
(import "spectest" "global_i32" (global i32))
(func (result i32) (global.get 1))
)
"unknown global"
)
(assert_invalid
(module
(import "spectest" "global_i32" (global i32))
(global i32 (i32.const 0))
(func (result i32) (global.get 2))
)
"unknown global"
)
;; global.set with invalid index
(assert_invalid
(module (func (i32.const 0) (global.set 0)))
"unknown global"
)
(assert_invalid
(module
(global i32 (i32.const 0))
(func (i32.const 0) (global.set 1))
)
"unknown global"
)
(assert_invalid
(module
(import "spectest" "global_i32" (global i32))
(func (i32.const 0) (global.set 1))
)
"unknown global"
)
(assert_invalid
(module
(import "spectest" "global_i32" (global i32))
(global i32 (i32.const 0))
(func (i32.const 0) (global.set 2))
)
"unknown global"
)
(assert_invalid
(module

View File

@@ -10,6 +10,7 @@
(func (export "func-i64->i64") (param i64) (result i64) (local.get 0))
(global (export "global-i32") i32 (i32.const 55))
(global (export "global-f32") f32 (f32.const 44))
(global (export "global-mut-i64") (mut i64) (i64.const 66))
(table (export "table-10-inf") 10 funcref)
;; (table (export "table-10-20") 10 20 funcref)
(memory (export "memory-2-inf") 2)
@@ -230,6 +231,7 @@
(module (import "test" "global-i32" (global i32)))
(module (import "test" "global-f32" (global f32)))
(module (import "test" "global-mut-i64" (global (mut i64))))
(assert_unlinkable
(module (import "test" "unknown" (global i32)))
@@ -240,6 +242,55 @@
"unknown import"
)
(assert_unlinkable
(module (import "test" "global-i32" (global i64)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-i32" (global f32)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-i32" (global f64)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-i32" (global (mut i32))))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-f32" (global i32)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-f32" (global i64)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-f32" (global f64)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-f32" (global (mut f32))))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-mut-i64" (global (mut i32))))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-mut-i64" (global (mut f32))))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-mut-i64" (global (mut f64))))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "global-mut-i64" (global i64)))
"incompatible import type"
)
(assert_unlinkable
(module (import "test" "func" (global i32)))
"incompatible import type"

View File

@@ -198,29 +198,29 @@
;; Invalid local index
(assert_invalid
(module (func $unbound-local (local i32 i64) (local.get 3)))
(module (func $unbound-local (local i32 i64) (local.get 3) drop))
"unknown local"
)
(assert_invalid
(module (func $large-local (local i32 i64) (local.get 14324343)))
(module (func $large-local (local i32 i64) (local.get 14324343) drop))
"unknown local"
)
(assert_invalid
(module (func $unbound-param (param i32 i64) (local.get 2)))
(module (func $unbound-param (param i32 i64) (local.get 2) drop))
"unknown local"
)
(assert_invalid
(module (func $large-param (param i32 i64) (local.get 714324343)))
(module (func $large-param (param i32 i64) (local.get 714324343) drop))
"unknown local"
)
(assert_invalid
(module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
(module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3) drop))
"unknown local"
)
(assert_invalid
(module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
(module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343) drop))
"unknown local"
)

View File

@@ -595,36 +595,6 @@
"type mismatch"
)
;; Invalid local index
(assert_invalid
(module (func $unbound-local (local i32 i64) (local.get 3)))
"unknown local"
)
(assert_invalid
(module (func $large-local (local i32 i64) (local.get 14324343)))
"unknown local"
)
(assert_invalid
(module (func $unbound-param (param i32 i64) (local.get 2)))
"unknown local"
)
(assert_invalid
(module (func $large-param (local i32 i64) (local.get 714324343)))
"unknown local"
)
(assert_invalid
(module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
"unknown local"
)
(assert_invalid
(module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
"unknown local"
)
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0))))
"type mismatch"
@@ -637,3 +607,33 @@
(module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0))))
"type mismatch"
)
;; Invalid local index
(assert_invalid
(module (func $unbound-local (local i32 i64) (local.tee 3 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $large-local (local i32 i64) (local.tee 14324343 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $unbound-param (param i32 i64) (local.tee 2 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $large-param (param i32 i64) (local.tee 714324343 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $unbound-mixed (param i32) (local i32 i64) (local.tee 3 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $large-mixed (param i64) (local i32 i64) (local.tee 214324343 (i32.const 0)) drop))
"unknown local"
)

View File

@@ -28,10 +28,19 @@
(unreachable) (select)
(unreachable) (i32.const 0) (select)
(unreachable) (i32.const 0) (i32.const 0) (select)
(unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select)
(unreachable) (f32.const 0) (i32.const 0) (select)
(unreachable)
)
(func (export "select_unreached_result_1") (result i32)
(unreachable) (i32.add (select))
)
(func (export "select_unreached_result_2") (result i64)
(unreachable) (i64.add (select (i64.const 0) (i32.const 0)))
)
;; As the argument of control constructs and instructions
(func (export "as-select-first") (param i32) (result i32)
@@ -287,22 +296,22 @@
(assert_return (invoke "as-convert-operand" (i32.const 1)) (i32.const 1))
(assert_invalid
(module (func $arity-0 (select (nop) (nop) (i32.const 1))))
(module (func $arity-0 (select (nop) (nop) (i32.const 1)) (drop)))
"type mismatch"
)
;; The first two operands should have the same type as each other
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1))))
(module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1))))
(module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1))))
(module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1)) (drop)))
"type mismatch"
)
@@ -412,3 +421,67 @@
)
"type mismatch"
)
;; Third operand must be i32
(assert_invalid
(module (func (select (i32.const 1) (i32.const 1) (i64.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (select (i32.const 1) (i32.const 1) (f32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (select (i32.const 1) (i32.const 1) (f64.const 1)) (drop)))
"type mismatch"
)
;; Result of select has type of first two operands
(assert_invalid
(module (func (result i32) (select (i64.const 1) (i64.const 1) (i32.const 1))))
"type mismatch"
)
;; Validation after unreachable
;; The first two operands should have the same type as each other
(assert_invalid
(module (func (unreachable) (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (unreachable) (select (i64.const 1) (i32.const 1) (i32.const 1)) (drop)))
"type mismatch"
)
;; Third operand must be i32
(assert_invalid
(module (func (unreachable) (select (i32.const 1) (i32.const 1) (i64.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (unreachable) (select (i32.const 1) (i64.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (unreachable) (select (i64.const 1)) (drop)))
"type mismatch"
)
;; Result of select has type of first two operands (type of second operand when first one is omitted)
(assert_invalid
(module (func (result i32) (unreachable) (select (i64.const 1) (i32.const 1))))
"type mismatch"
)
;; select always has non-empty result
(assert_invalid
(module (func (unreachable) (select)))
"type mismatch"
)

View File

@@ -125,12 +125,31 @@
end
local.get $res
)
(global $temp (mut i32) (i32.const 0))
(func $add_one_to_global (result i32)
(local i32)
(global.set $temp (i32.add (i32.const 1) (global.get $temp)))
(global.get $temp)
)
(func $add_one_to_global_and_drop
(drop (call $add_one_to_global))
)
(func (export "not-quite-a-tree") (result i32)
call $add_one_to_global
call $add_one_to_global
call $add_one_to_global_and_drop
i32.add
)
)
(assert_return (invoke "fac-expr" (i64.const 25)) (i64.const 7034535277573963776))
(assert_return (invoke "fac-stack" (i64.const 25)) (i64.const 7034535277573963776))
(assert_return (invoke "fac-mixed" (i64.const 25)) (i64.const 7034535277573963776))
(assert_return (invoke "not-quite-a-tree") (i32.const 3))
(assert_return (invoke "not-quite-a-tree") (i32.const 9))
;; Syntax of flat call_indirect