resolve conflict, replace two primary map to hash map

This commit is contained in:
Bo Yao
2021-04-20 16:50:05 -07:00
parent 2a3efeb1d2
commit 92af25a585
117 changed files with 11350 additions and 1540 deletions

View File

@@ -3,11 +3,3 @@ rustflags = [
# Put the VM functions in the dynamic symbol table. # Put the VM functions in the dynamic symbol table.
"-C", "link-arg=-Wl,-E", "-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",
]

View File

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

View File

@@ -19,7 +19,7 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: 1.49 toolchain: "1.50"
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Install LLVM (Linux) - name: Install LLVM (Linux)

View File

@@ -41,26 +41,26 @@ jobs:
include: include:
- build: linux-x64 - build: linux-x64
os: ubuntu-18.04 os: ubuntu-18.04
rust: 1.49 rust: "1.50"
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz' llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz'
artifact_name: 'wasmer-linux-amd64' artifact_name: 'wasmer-linux-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_linux' cross_compilation_artifact_name: 'cross_compiled_from_linux'
run_integration_tests: true run_integration_tests: true
- build: macos-x64 - build: macos-x64
os: macos-latest os: macos-latest
rust: 1.49 rust: "1.50"
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/darwin-amd64.tar.gz' llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/darwin-amd64.tar.gz'
artifact_name: 'wasmer-darwin-amd64' artifact_name: 'wasmer-darwin-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_mac' cross_compilation_artifact_name: 'cross_compiled_from_mac'
run_integration_tests: true run_integration_tests: true
- build: macos-arm64 - build: macos-arm64
os: macos-11.0 os: macos-11.0
rust: 1.49 rust: "1.50"
target: aarch64-apple-darwin target: aarch64-apple-darwin
artifact_name: 'wasmer-darwin-arm64' artifact_name: 'wasmer-darwin-arm64'
- build: windows-x64 - build: windows-x64
os: windows-latest os: windows-latest
rust: 1.49 rust: "1.50"
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/windows-amd64.tar.gz' # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/windows-amd64.tar.gz'
artifact_name: 'wasmer-windows-amd64' artifact_name: 'wasmer-windows-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_win' cross_compilation_artifact_name: 'cross_compiled_from_win'
@@ -68,7 +68,7 @@ jobs:
- build: linux-aarch64 - build: linux-aarch64
os: [self-hosted, linux, ARM64] os: [self-hosted, linux, ARM64]
random_sccache_port: true random_sccache_port: true
rust: 1.49 rust: "1.50"
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-aarch64.tar.gz' llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-aarch64.tar.gz'
artifact_name: 'wasmer-linux-aarch64' artifact_name: 'wasmer-linux-aarch64'
run_integration_tests: false run_integration_tests: false
@@ -289,12 +289,12 @@ jobs:
include: include:
- build: linux-musl-x64 - build: linux-musl-x64
image: alpine:latest image: alpine:latest
rust: 1.49 rust: "1.50"
artifact_name: 'wasmer-linux-musl-amd64' artifact_name: 'wasmer-linux-musl-amd64'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: addnab/docker-run-action@v1 - uses: addnab/docker-run-action@v3
with: with:
image: ${{ matrix.image }} image: ${{ matrix.image }}
options: -v ${{ github.workspace }}:/work options: -v ${{ github.workspace }}:/work

View File

@@ -4,10 +4,13 @@
[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/
Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/CHANGELOG.md).
## **[Unreleased]** ## **[Unreleased]**
### Added ### Added
- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Add a new CHANGELOG.md specific to our C API to make it easier for users primarily consuming our C API to keep up to date with changes that affect them.
- [#2103](https://github.com/wasmerio/wasmer/pull/2103) Add middleware (incl. metering) in the C API. - [#2103](https://github.com/wasmerio/wasmer/pull/2103) Add middleware (incl. metering) in the C API.
- [#2003](https://github.com/wasmerio/wasmer/pull/2003) Wasmer works with musl, and is built, tested and packaged for musl. - [#2003](https://github.com/wasmerio/wasmer/pull/2003) Wasmer works with musl, and is built, tested and packaged for musl.
- [#2116](https://github.com/wasmerio/wasmer/pull/2116) Add a package for Windows that is not an installer, but all the `lib` and `include` files as for macOS and Linux. - [#2116](https://github.com/wasmerio/wasmer/pull/2116) Add a package for Windows that is not an installer, but all the `lib` and `include` files as for macOS and Linux.
@@ -27,6 +30,8 @@
- [#2149](https://github.com/wasmerio/wasmer/pull/2144) `wasmer-engine-native` looks for clang-11 instead of clang-10. - [#2149](https://github.com/wasmerio/wasmer/pull/2144) `wasmer-engine-native` looks for clang-11 instead of clang-10.
### Fixed ### Fixed
- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Fix ownership in Wasm C API of `wasm_extern_as_func`, `wasm_extern_as_memory`, `wasm_extern_as_table`, `wasm_extern_as_global`, `wasm_func_as_extern`, `wasm_memory_as_extern`, `wasm_table_as_extern`, and `wasm_global_as_extern`. These functions no longer allocate memory and thus their results should not be freed. This is a breaking change to align more closely with the Wasm C API's stated ownership.
- [#2210](https://github.com/wasmerio/wasmer/pull/2210) Fix a memory leak in the Wasm C API in the strings used to identify imports and exports coming from user code.
- [#2108](https://github.com/wasmerio/wasmer/pull/2108) The Object Native Engine generates code that now compiles correctly with C++. - [#2108](https://github.com/wasmerio/wasmer/pull/2108) The Object Native Engine generates code that now compiles correctly with C++.
- [#2125](https://github.com/wasmerio/wasmer/pull/2125) Fix RUSTSEC-2021-0023. - [#2125](https://github.com/wasmerio/wasmer/pull/2125) Fix RUSTSEC-2021-0023.
- [#2155](https://github.com/wasmerio/wasmer/pull/2155) Fix the implementation of shift and rotate in the LLVM compiler. - [#2155](https://github.com/wasmerio/wasmer/pull/2155) Fix the implementation of shift and rotate in the LLVM compiler.

15
Cargo.lock generated
View File

@@ -770,6 +770,16 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "field-offset"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf539fba70056b50f40a22e0da30639518a12ee18c35807858a63b158cb6dde7"
dependencies = [
"memoffset",
"rustc_version 0.3.3",
]
[[package]] [[package]]
name = "filetime" name = "filetime"
version = "0.2.14" version = "0.2.14"
@@ -1162,9 +1172,9 @@ dependencies = [
[[package]] [[package]]
name = "loupe" name = "loupe"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1acf065b51eb58abbc66a07c27ec63142205d339a9f5093dc3e1d7cda3d5c9a3" checksum = "d79b0cc3aa7552a59274f642a0a6e7419b7f5438aba06a0a82825918ba69f0e6"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"loupe-derive", "loupe-derive",
@@ -2434,6 +2444,7 @@ dependencies = [
"cbindgen", "cbindgen",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"enumset", "enumset",
"field-offset",
"inline-c", "inline-c",
"lazy_static", "lazy_static",
"libc", "libc",

121
Makefile
View File

@@ -366,9 +366,9 @@ build-wasmer-debug:
# incremental = false # incremental = false
# codegen-units = 1 # codegen-units = 1
# rpath = false # rpath = false
build-wasmer-headless-minimal: RUSTFLAGS += "-C panic=abort" build-wasmer-headless-minimal: RUSTFLAGS += -C panic=abort
build-wasmer-headless-minimal: build-wasmer-headless-minimal:
RUSTFLAGS=${RUSTFLAGS} xargo build --target $(HOST_TARGET) --release --manifest-path=lib/cli/Cargo.toml --no-default-features --features headless-minimal --bin wasmer-headless RUSTFLAGS="${RUSTFLAGS}" xargo build --target $(HOST_TARGET) --release --manifest-path=lib/cli/Cargo.toml --no-default-features --features headless-minimal --bin wasmer-headless
ifeq ($(IS_DARWIN), 1) ifeq ($(IS_DARWIN), 1)
strip -u target/$(HOST_TARGET)/release/wasmer-headless strip -u target/$(HOST_TARGET)/release/wasmer-headless
else else
@@ -379,7 +379,7 @@ else
endif endif
endif endif
WAPM_VERSION = master # v0.5.0 WAPM_VERSION = v0.5.1
get-wapm: get-wapm:
[ -d "wapm-cli" ] || git clone --branch $(WAPM_VERSION) https://github.com/wasmerio/wapm-cli.git [ -d "wapm-cli" ] || git clone --branch $(WAPM_VERSION) https://github.com/wasmerio/wapm-cli.git
@@ -394,82 +394,87 @@ endif
build-docs: build-docs:
cargo doc --release $(compiler_features) --document-private-items --no-deps --workspace cargo doc --release $(compiler_features) --document-private-items --no-deps --workspace
build-docs-capi: capi-setup:
cd lib/c-api/doc/deprecated/ && doxygen doxyfile ifeq ($(IS_WINDOWS), 1)
cargo doc --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,jit,object-file,native,cranelift,wasi $(capi_default_features) RUSTFLAGS += -C target-feature=+crt-static
endif
build-capi: build-docs-capi: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ cd lib/c-api/doc/deprecated/ && doxygen doxyfile
RUSTFLAGS="${RUSTFLAGS}" cargo doc --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,jit,object-file,native,cranelift,wasi $(capi_default_features)
build-capi: capi-setup
RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,wasi,middlewares $(capi_default_features) $(capi_compiler_features) --no-default-features --features deprecated,wat,jit,native,object-file,wasi,middlewares $(capi_default_features) $(capi_compiler_features)
build-capi-singlepass: build-capi-singlepass: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,singlepass,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,jit,native,object-file,singlepass,wasi,middlewares $(capi_default_features)
build-capi-singlepass-jit: build-capi-singlepass-jit: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,singlepass,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,jit,singlepass,wasi,middlewares $(capi_default_features)
build-capi-singlepass-native: build-capi-singlepass-native: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,native,singlepass,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,native,singlepass,wasi,middlewares $(capi_default_features)
build-capi-singlepass-object-file: build-capi-singlepass-object-file: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,object-file,singlepass,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,object-file,singlepass,wasi,middlewares $(capi_default_features)
build-capi-cranelift: build-capi-cranelift: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,cranelift,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,jit,native,object-file,cranelift,wasi,middlewares $(capi_default_features)
build-capi-cranelift-system-libffi: build-capi-cranelift-system-libffi: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,cranelift,wasi,middlewares,system-libffi $(capi_default_features) --no-default-features --features deprecated,wat,jit,native,object-file,cranelift,wasi,middlewares,system-libffi $(capi_default_features)
build-capi-cranelift-jit: build-capi-cranelift-jit: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,cranelift,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,jit,cranelift,wasi,middlewares $(capi_default_features)
build-capi-cranelift-native: build-capi-cranelift-native: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,native,cranelift,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,native,cranelift,wasi,middlewares $(capi_default_features)
build-capi-cranelift-object-file: build-capi-cranelift-object-file: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,native,object-file,cranelift,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,native,object-file,cranelift,wasi,middlewares $(capi_default_features)
build-capi-llvm: build-capi-llvm: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,native,object-file,llvm,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,jit,native,object-file,llvm,wasi,middlewares $(capi_default_features)
build-capi-llvm-jit: build-capi-llvm-jit: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,jit,llvm,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,jit,llvm,wasi,middlewares $(capi_default_features)
build-capi-llvm-native: build-capi-llvm-native: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,native,llvm,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,native,llvm,wasi,middlewares $(capi_default_features)
build-capi-llvm-object-file: build-capi-llvm-object-file: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features deprecated,wat,object-file,llvm,wasi,middlewares $(capi_default_features) --no-default-features --features deprecated,wat,object-file,llvm,wasi,middlewares $(capi_default_features)
# Headless (we include the minimal to be able to run) # Headless (we include the minimal to be able to run)
build-capi-headless-jit: build-capi-headless-jit: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features jit,wasi --no-default-features --features jit,wasi
build-capi-headless-native: build-capi-headless-native: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features native,wasi --no-default-features --features native,wasi
build-capi-headless-object-file: build-capi-headless-object-file: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features object-file,wasi --no-default-features --features object-file,wasi
build-capi-headless-all: build-capi-headless-all: capi-setup
cargo build --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" cargo build --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features jit,native,object-file,wasi --no-default-features --features jit,native,object-file,wasi
########### ###########
@@ -724,23 +729,23 @@ install-wasmer-headless-minimal:
update-testsuite: update-testsuite:
git subtree pull --prefix tests/wast/spec https://github.com/WebAssembly/testsuite.git master --squash git subtree pull --prefix tests/wast/spec https://github.com/WebAssembly/testsuite.git master --squash
lint-packages: RUSTFLAGS += "-D dead-code -D nonstandard-style -D unused-imports -D unused-mut -D unused-variables -D unused-unsafe -D unreachable-patterns -D bad-style -D improper-ctypes -D unused-allocation -D unused-comparisons -D while-true -D unconditional-recursion -D bare-trait-objects" # TODO: add `-D missing-docs` # TODO: add `-D function_item_references` (not available on Rust 1.47, try when upgrading) lint-packages: RUSTFLAGS += -D dead-code -D nonstandard-style -D unused-imports -D unused-mut -D unused-variables -D unused-unsafe -D unreachable-patterns -D bad-style -D improper-ctypes -D unused-allocation -D unused-comparisons -D while-true -D unconditional-recursion -D bare-trait-objects # TODO: add `-D missing-docs` # TODO: add `-D function_item_references` (not available on Rust 1.47, try when upgrading)
lint-packages: lint-packages:
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-c-api RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-c-api
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-vm RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-vm
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-types RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-types
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-wasi RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-wasi
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-object RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-object
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-engine-native RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-engine-native
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-engine-jit RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-engine-jit
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-compiler RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-compiler
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-compiler-cranelift RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-compiler-cranelift
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-compiler-singlepass RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-compiler-singlepass
RUSTFLAGS=${RUSTFLAGS} cargo clippy --manifest-path lib/cli/Cargo.toml $(compiler_features) RUSTFLAGS="${RUSTFLAGS}" cargo clippy --manifest-path lib/cli/Cargo.toml $(compiler_features)
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-cache RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-cache
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-engine RUSTFLAGS="${RUSTFLAGS}" cargo clippy -p wasmer-engine
RUSTFLAGS=${RUSTFLAGS} cargo clippy --manifest-path fuzz/Cargo.toml $(compiler_features) RUSTFLAGS="${RUSTFLAGS}" cargo clippy --manifest-path fuzz/Cargo.toml $(compiler_features)
lint-formatting: lint-formatting:
cargo fmt --all -- --check cargo fmt --all -- --check

View File

@@ -29,7 +29,7 @@
[Wasmer](https://wasmer.io/) enables super lightweight containers based on [WebAssembly](https://webassembly.org/) that can run anywhere: from Desktop to the Cloud and IoT devices, and also embedded in [*any programming language*](https://github.com/wasmerio/wasmer#language-integrations). [Wasmer](https://wasmer.io/) enables super lightweight containers based on [WebAssembly](https://webassembly.org/) that can run anywhere: from Desktop to the Cloud and IoT devices, and also embedded in [*any programming language*](https://github.com/wasmerio/wasmer#language-integrations).
> This readme is also available in: [🇨🇳 中文-Chinese](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md) • [🇪🇸 Español-Spanish](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇫🇷 Français-French](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md). > This readme is also available in: [🇨🇳 中文-Chinese](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md) • [🇪🇸 Español-Spanish](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇫🇷 Français-French](https://github.com/wasmerio/wasmer/blob/master/docs/fr/README.md) • [🇯🇵 日本語-Japanese](https://github.com/wasmerio/wasmer/blob/master/docs/ja/README.md).
## Features ## Features
@@ -66,7 +66,7 @@ iwr https://win.wasmer.io -useb | iex
#### Executing a WebAssembly file #### Executing a WebAssembly file
After installing Wasmer you should be ready to execute your first WebAssemby file! 🎉 After installing Wasmer you should be ready to execute your first WebAssembly file! 🎉
You can start by running QuickJS: [qjs.wasm](https://registry-cdn.wapm.io/contents/_/quickjs/0.0.3/build/qjs.wasm) You can start by running QuickJS: [qjs.wasm](https://registry-cdn.wapm.io/contents/_/quickjs/0.0.3/build/qjs.wasm)
@@ -108,7 +108,7 @@ qjs >
[rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg [rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg
[rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api [rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api
[`wasmer` rust crate]: https://crates.io/crates/wasmer/ [`wasmer` rust crate]: https://crates.io/crates/wasmer/
[rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer_runtime [rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer
[c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg [c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg
[c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api [c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api

View File

@@ -1,7 +1,6 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{black_box, criterion_group, criterion_main, Criterion};
use wasmer::*; use wasmer::*;
use wasmer_engine_jit::JIT;
static BASIC_WAT: &str = r#"(module static BASIC_WAT: &str = r#"(module
(func $multiply (import "env" "multiply") (param i32 i32) (result i32)) (func $multiply (import "env" "multiply") (param i32 i32) (result i32))
@@ -147,7 +146,7 @@ pub fn run_basic_dynamic_function(store: &Store, compiler_name: &str, c: &mut Cr
); );
} }
fn run_static_benchmarks(c: &mut Criterion) { fn run_static_benchmarks(_c: &mut Criterion) {
#[cfg(feature = "llvm")] #[cfg(feature = "llvm")]
{ {
let store = Store::new(&JIT::new(wasmer_compiler_llvm::LLVM::new()).engine()); let store = Store::new(&JIT::new(wasmer_compiler_llvm::LLVM::new()).engine());
@@ -167,7 +166,7 @@ fn run_static_benchmarks(c: &mut Criterion) {
} }
} }
fn run_dynamic_benchmarks(c: &mut Criterion) { fn run_dynamic_benchmarks(_c: &mut Criterion) {
#[cfg(feature = "llvm")] #[cfg(feature = "llvm")]
{ {
let store = Store::new(&JIT::new(wasmer_compiler_llvm::LLVM::new()).engine()); let store = Store::new(&JIT::new(wasmer_compiler_llvm::LLVM::new()).engine());

View File

@@ -29,7 +29,7 @@
[Wasmer](https://wasmer.io/) 使得能够基于 [WebAssembly](https://webassembly.org/)其可以在任何地方运行超轻型容器从桌面到云和的IoT装置并且也嵌入在 [*任何编程语言*](https://github.com/wasmerio/wasmer#language-integrations). [Wasmer](https://wasmer.io/) 使得能够基于 [WebAssembly](https://webassembly.org/)其可以在任何地方运行超轻型容器从桌面到云和的IoT装置并且也嵌入在 [*任何编程语言*](https://github.com/wasmerio/wasmer#language-integrations).
> This readme is also available in: [🇬🇧 English-英文](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇪🇸 Español-西班牙语](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇫🇷 Français-法语/法语](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md). > This readme is also available in: [🇬🇧 English-英文](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇪🇸 Español-西班牙语](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇫🇷 Français-法语](https://github.com/wasmerio/wasmer/blob/master/docs/fr/README.md) • [🇯🇵 日本語-日文](https://github.com/wasmerio/wasmer/blob/master/docs/ja/README.md).
## 特征 ## 特征
@@ -108,7 +108,7 @@ qjs >
[rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg [rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg
[rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api [rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api
[`wasmer` rust crate]: https://crates.io/crates/wasmer/ [`wasmer` rust crate]: https://crates.io/crates/wasmer/
[rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer_runtime [rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer
[c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg [c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg
[c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api [c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api

View File

@@ -29,7 +29,7 @@
[Wasmer](https://wasmer.io/) hace posible tener contenedores ultraligeros basados en [WebAssembly](https://webassembly.org/) que pueden ser ejecutados en cualquier sitio: desde tu ordenador hasta la nube y dispositivos de IoT, además de poder ser ejecutados [*en cualquier lenguaje de programación*](https://github.com/wasmerio/wasmer#language-integrations). [Wasmer](https://wasmer.io/) hace posible tener contenedores ultraligeros basados en [WebAssembly](https://webassembly.org/) que pueden ser ejecutados en cualquier sitio: desde tu ordenador hasta la nube y dispositivos de IoT, además de poder ser ejecutados [*en cualquier lenguaje de programación*](https://github.com/wasmerio/wasmer#language-integrations).
> This README is also available in: [🇬🇧 English-Inglés](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇫🇷 Français-Francés](https://github.com/wasmerio/wasmer/blob/master/docs/fr/README.md) • [🇨🇳 中文-Chino](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md). > This README is also available in: [🇬🇧 English-Inglés](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇫🇷 Français-Francés](https://github.com/wasmerio/wasmer/blob/master/docs/fr/README.md) • [🇨🇳 中文-Chino](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md) • [🇯🇵 日本語-japonés](https://github.com/wasmerio/wasmer/blob/master/docs/ja/README.md).
## Funcionalidades ## Funcionalidades
@@ -107,7 +107,7 @@ qjs >
[rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg [rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg
[rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api [rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api
[`wasmer` en crates.io]: https://crates.io/crates/wasmer/ [`wasmer` en crates.io]: https://crates.io/crates/wasmer/
[rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer_runtime [rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer
[c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg [c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg
[c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api [c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api

View File

@@ -29,7 +29,7 @@
[Wasmer](https://wasmer.io/) permet l'utilisation de conteneurs super légers basés sur [WebAssembly](https://webassembly.org/) qui peuvent fonctionner n'importe où : du bureau au cloud en passant par les appareils IoT, et également intégrés dans [*une multitude de langages de programmation*](https://github.com/wasmerio/wasmer#language-integrations). [Wasmer](https://wasmer.io/) permet l'utilisation de conteneurs super légers basés sur [WebAssembly](https://webassembly.org/) qui peuvent fonctionner n'importe où : du bureau au cloud en passant par les appareils IoT, et également intégrés dans [*une multitude de langages de programmation*](https://github.com/wasmerio/wasmer#language-integrations).
> This readme is also available in: [🇬🇧 English-Anglaise](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇪🇸 Español-Espagnol](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇨🇳 中文-Chinoise](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md) > This readme is also available in: [🇬🇧 English-Anglaise](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇪🇸 Español-Espagnol](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇨🇳 中文-Chinoise](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md) • [🇯🇵 日本語-japonais](https://github.com/wasmerio/wasmer/blob/master/docs/ja/README.md)
## Fonctionnalités ## Fonctionnalités
@@ -107,7 +107,7 @@ qjs >
[rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg [rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg
[rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api [rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api
[`wasmer` rust crate]: https://crates.io/crates/wasmer/ [`wasmer` rust crate]: https://crates.io/crates/wasmer/
[rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer_runtime [rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer
[c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg [c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg
[c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api [c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api

191
docs/ja/README.md Normal file
View File

@@ -0,0 +1,191 @@
<div align="center">
<a href="https://wasmer.io" target="_blank" rel="noopener noreferrer">
<img width="300" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/logo.png" alt="Wasmerロゴ">
</a>
<p>
<a href="https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild">
<img src="https://github.com/wasmerio/wasmer/workflows/build/badge.svg?style=flat-square" alt="ビルドステータス">
</a>
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square" alt="ライセンス">
</a>
<a href="https://slack.wasmer.io">
<img src="https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square" alt="Slackチャンネル">
</a>
</p>
<h3>
<a href="https://wasmer.io/">Website</a>
<span></span>
<a href="https://docs.wasmer.io">Docs</a>
<span></span>
<a href="https://slack.wasmer.io/">Chat</a>
</h3>
</div>
<br />
[Wasmer](https://wasmer.io/) は、[WebAssembly](https://webassembly.org/) をベースとした非常に軽量なコンテナを実現します。デスクトップからクラウドや IoT デバイス上まで、どんな環境でも実行でき、さらに[*任意のプログラミング言語*](#他の言語とのインテグレーション)に埋め込むこともできます。
> この readme は、次の言語でも利用可能です。[🇨🇳 中文-Chinese](https://github.com/wasmerio/wasmer/blob/master/docs/cn/README.md) • [🇬🇧 英語-English](https://github.com/wasmerio/wasmer/blob/master/README.md) • [🇪🇸 Español-Spanish](https://github.com/wasmerio/wasmer/blob/master/docs/es/README.md) • [🇫🇷 Français-French](https://github.com/wasmerio/wasmer/blob/master/docs/fr/README.md)
## 機能
* **高速かつ安全**。WebAssembly を完全なサンドボックス環境内で*ネイティブに近い*スピードで実行します。
* **プラガブル**。異なるコンパイルフレームワーク (LLVM、Cranelift など...) をサポートしているため、ニーズに合った最適なフレームワークを選択できます。
* **ユニバーサル**。どんなプラットフォーム上 (macOS、Linux、Windows) でも、どんな*チップセット*上でも実行できます。
* **標準に準拠**。ランタイムは[公式の WebAssembly テストスイート](https://github.com/WebAssembly/testsuite)に通っており、[WASI](https://github.com/WebAssembly/WASI) と [Emscripten](https://emscripten.org/) をサポートします。
## クイックスタート
Wasmer は依存関係なしで動作します。以下のコマンドでインストーラーを使用してインストールできます。
```sh
curl https://get.wasmer.io -sSfL | sh
```
<details>
<summary>PowerShell の場合 (Windows)</summary>
<p>
```powershell
iwr https://win.wasmer.io -useb | iex
```
</p>
</details>
> Homebrew、Scoop、Cargo など、他のインストール方法については、[wasmer-install](https://github.com/wasmerio/wasmer-install) を参照してください。
#### WebAssembly ファイルの実行
Wasmer をインストールしたら、初めての WebAssembly ファイルの実行準備が完了です! 🎉
QuickJS ([qjs.wasm](https://registry-cdn.wapm.io/contents/_/quickjs/0.0.3/build/qjs.wasm)) を実行することで、すぐに始められます。
```bash
$ wasmer qjs.wasm
QuickJS - Type "\h" for help
qjs >
```
#### 次にできること
- [Rust アプリケーションから Wasmer を使用する](https://docs.wasmer.io/integrations/rust)
- [WAPM で Wasm パッケージを公開する](https://docs.wasmer.io/ecosystem/wapm/publishing-your-package)
- [Wasmer についてさらに学ぶ](https://medium.com/wasmer/)
## 他の言語とのインテグレーション
📦 Wasmer ランタイムは**他の言語に組み込んで**使用できるため、WebAssembly は_どんな場所でも_利用できます。
| &nbsp; | Language | Package | Docs |
|-|-|-|-|
| ![Rust logo] | [**Rust**][Rust integration] | [`wasmer` Rust crate] | [Docs][rust docs]
| ![C logo] | [**C/C++**][C integration] | [`wasmer.h` headers] | [Docs][c docs] |
| ![C# logo] | [**C#**][C# integration] | [`WasmerSharp` NuGet package] | [Docs][c# docs] |
| ![D logo] | [**D**][D integration] | [`wasmer` Dub package] | [Docs][d docs] |
| ![Python logo] | [**Python**][Python integration] | [`wasmer` PyPI package] | [Docs][python docs] |
| ![JS logo] | [**Javascript**][JS integration] | [`@wasmerio` NPM packages] | [Docs][js docs] |
| ![Go logo] | [**Go**][Go integration] | [`wasmer` Go package] | [Docs][go docs] |
| ![PHP logo] | [**PHP**][PHP integration] | [`wasm` PECL package] | [Docs][php docs] |
| ![Ruby logo] | [**Ruby**][Ruby integration] | [`wasmer` Ruby Gem] | [Docs][ruby docs] |
| ![Java logo] | [**Java**][Java integration] | [`wasmer/wasmer-jni` Bintray package] | [Docs][java docs] |
| ![Elixir logo] | [**Elixir**][Elixir integration] | [`wasmex` hex package] | [Docs][elixir docs] |
| ![R logo] | [**R**][R integration] | *公開パッケージなし* | [Docs][r docs] |
| ![Postgres logo] | [**Postgres**][Postgres integration] | *公開パッケージなし* | [Docs][postgres docs] |
| | [**Swift**][Swift integration] | *公開パッケージなし* | |
[👋 言語が見当たらない?](https://github.com/wasmerio/wasmer/issues/new?assignees=&labels=%F0%9F%8E%89+enhancement&template=---feature-request.md&title=)
[rust logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/rust.svg
[rust integration]: https://github.com/wasmerio/wasmer/tree/master/lib/api
[`wasmer` rust crate]: https://crates.io/crates/wasmer/
[rust docs]: https://wasmerio.github.io/wasmer/crates/wasmer
[c logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/c.svg
[c integration]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api
[`wasmer.h` headers]: https://wasmerio.github.io/wasmer/c/
[c docs]: https://wasmerio.github.io/wasmer/c/
[c# logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/csharp.svg
[c# integration]: https://github.com/migueldeicaza/WasmerSharp
[`wasmersharp` nuget package]: https://www.nuget.org/packages/WasmerSharp/
[c# docs]: https://migueldeicaza.github.io/WasmerSharp/
[d logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/d.svg
[d integration]: https://github.com/chances/wasmer-d
[`wasmer` Dub package]: https://code.dlang.org/packages/wasmer
[d docs]: https://chances.github.io/wasmer-d
[python logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/python.svg
[python integration]: https://github.com/wasmerio/wasmer-python
[`wasmer` pypi package]: https://pypi.org/project/wasmer/
[python docs]: https://github.com/wasmerio/wasmer-python#api-of-the-wasmer-extensionmodule
[go logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/go.svg
[go integration]: https://github.com/wasmerio/wasmer-go
[`wasmer` go package]: https://pkg.go.dev/github.com/wasmerio/wasmer-go/wasmer
[go docs]: https://pkg.go.dev/github.com/wasmerio/wasmer-go/wasmer?tab=doc
[php logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/php.svg
[php integration]: https://github.com/wasmerio/wasmer-php
[`wasm` pecl package]: https://pecl.php.net/package/wasm
[php docs]: https://wasmerio.github.io/wasmer-php/wasm/
[js logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/js.svg
[js integration]: https://github.com/wasmerio/wasmer-js
[`@wasmerio` npm packages]: https://www.npmjs.com/org/wasmer
[js docs]: https://docs.wasmer.io/integrations/js/reference-api
[ruby logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/ruby.svg
[ruby integration]: https://github.com/wasmerio/wasmer-ruby
[`wasmer` ruby gem]: https://rubygems.org/gems/wasmer
[ruby docs]: https://www.rubydoc.info/gems/wasmer/
[java logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/java.svg
[java integration]: https://github.com/wasmerio/wasmer-java
[`wasmer/wasmer-jni` bintray package]: https://bintray.com/wasmer/wasmer-jni/wasmer-jni
[java docs]: https://github.com/wasmerio/wasmer-java/#api-of-the-wasmer-library
[elixir logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/elixir.svg
[elixir integration]: https://github.com/tessi/wasmex
[elixir docs]: https://hexdocs.pm/wasmex/api-reference.html
[`wasmex` hex package]: https://hex.pm/packages/wasmex
[r logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/r.svg
[r integration]: https://github.com/dirkschumacher/wasmr
[r docs]: https://github.com/dirkschumacher/wasmr#example
[postgres logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/postgres.svg
[postgres integration]: https://github.com/wasmerio/wasmer-postgres
[postgres docs]: https://github.com/wasmerio/wasmer-postgres#usage--documentation
[swift integration]: https://github.com/AlwaysRightInstitute/SwiftyWasmer
## コントリビューション
**どんな形での貢献も歓迎です。コミュニティの新しいメンバーからの貢献は特に歓迎します。** 💜
Wasmer ランタイムのビルド方法は、[素晴らしいドキュメント](https://docs.wasmer.io/ecosystem/wasmer/building-from-source)で確認できます!
### テスト
テストを実行したいですか? [Wasmer docs で方法を説明](https://docs.wasmer.io/ecosystem/wasmer/building-from-source/testing)しています。
## コミュニティ
Wasmer には、開発者とコントリビューターの素晴らしいコミュニティがあります。ようこそ! あなたも是非参加してください! 👋
### チャンネル
- [Slack](https://slack.wasmer.io/)
- [Twitter](https://twitter.com/wasmerio)
- [Facebook](https://www.facebook.com/wasmerio)
- [Email](mailto:hello@wasmer.io)

View File

@@ -116,9 +116,9 @@ fn main() -> anyhow::Result<()> {
maximum: Some(6), maximum: Some(6),
} }
); );
// Now demonstarte that the function we grew the table with is actually in the table. // Now demonstrate that the function we grew the table with is actually in the table.
for table_index in 3..6 { for table_index in 3..6 {
if let Value::FuncRef(f) = guest_table.get(table_index as _).unwrap() { if let Value::FuncRef(Some(f)) = guest_table.get(table_index as _).unwrap() {
let result = f.call(&[Value::I32(1), Value::I32(9)])?; let result = f.call(&[Value::I32(1), Value::I32(9)])?;
assert_eq!(result[0], Value::I32(10)); assert_eq!(result[0], Value::I32(10));
} else { } else {
@@ -140,7 +140,7 @@ fn main() -> anyhow::Result<()> {
// Now demonstrate that the host and guest see the same table and that both // Now demonstrate that the host and guest see the same table and that both
// get the same result. // get the same result.
for table_index in 3..6 { for table_index in 3..6 {
if let Value::FuncRef(f) = guest_table.get(table_index as _).unwrap() { if let Value::FuncRef(Some(f)) = guest_table.get(table_index as _).unwrap() {
let result = f.call(&[Value::I32(1), Value::I32(9)])?; let result = f.call(&[Value::I32(1), Value::I32(9)])?;
assert_eq!(result[0], Value::I32(10)); assert_eq!(result[0], Value::I32(10));
} else { } else {

4
fuzz/Cargo.lock generated
View File

@@ -511,9 +511,9 @@ dependencies = [
[[package]] [[package]]
name = "loupe" name = "loupe"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1acf065b51eb58abbc66a07c27ec63142205d339a9f5093dc3e1d7cda3d5c9a3" checksum = "d79b0cc3aa7552a59274f642a0a6e7419b7f5438aba06a0a82825918ba69f0e6"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"loupe-derive", "loupe-derive",

9
fuzzbuzz.yaml Normal file
View File

@@ -0,0 +1,9 @@
wasmer:
language: rust
features:
- jit
- cranelift
- singlepass
deps:
- run: apt update
- run: apt install -y zlib1g-dev libffi-dev build-essential

View File

@@ -100,3 +100,8 @@ default-native = [
"native", "native",
"default-engine" "default-engine"
] ]
# experimental / in-development features
experimental-reference-types-extern-ref = [
"wasmer-types/experimental-reference-types-extern-ref",
]

View File

@@ -1,7 +1,7 @@
use crate::exports::{ExportError, Exportable}; use crate::exports::{ExportError, Exportable};
use crate::externals::Extern; use crate::externals::Extern;
use crate::store::Store; use crate::store::Store;
use crate::types::Val; use crate::types::{Val, ValFuncRef};
use crate::FunctionType; use crate::FunctionType;
use crate::NativeFunc; use crate::NativeFunc;
use crate::RuntimeError; use crate::RuntimeError;
@@ -18,7 +18,7 @@ use std::sync::Arc;
use wasmer_engine::{Export, ExportFunction, ExportFunctionMetadata}; use wasmer_engine::{Export, ExportFunction, ExportFunctionMetadata};
use wasmer_vm::{ use wasmer_vm::{
raise_user_trap, resume_panic, wasmer_call_trampoline, ImportInitializerFuncPtr, raise_user_trap, resume_panic, wasmer_call_trampoline, ImportInitializerFuncPtr,
VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMExportFunction, VMFuncRef, VMFunctionBody,
VMFunctionEnvironment, VMFunctionKind, VMTrampoline, VMFunctionEnvironment, VMFunctionKind, VMTrampoline,
}; };
@@ -70,6 +70,30 @@ pub struct Function {
pub(crate) exported: ExportFunction, pub(crate) exported: ExportFunction,
} }
impl wasmer_types::WasmValueType for Function {
/// Write the value.
unsafe fn write_value_to(&self, p: *mut i128) {
let func_ref =
Val::into_vm_funcref(&Val::FuncRef(Some(self.clone())), &self.store).unwrap();
std::ptr::write(p as *mut VMFuncRef, func_ref);
}
/// Read the value.
// TODO(reftypes): this entire function should be cleaned up, `dyn Any` should
// ideally be removed
unsafe fn read_value_from(store: &dyn std::any::Any, p: *const i128) -> Self {
let func_ref = std::ptr::read(p as *const VMFuncRef);
let store = store.downcast_ref::<Store>().expect("Store expected in `Function::read_value_from`. If you see this error message it likely means you're using a function ref in a place we don't yet support it -- sorry about the inconvenience.");
match Val::from_vm_funcref(func_ref, store) {
Val::FuncRef(Some(fr)) => fr,
// these bottom two cases indicate bugs in `wasmer-types` or elsewhere.
// They should never be triggered, so we just panic.
Val::FuncRef(None) => panic!("Null funcref found in `Function::read_value_from`!"),
other => panic!("Invalid value in `Function::read_value_from`: {:?}", other),
}
}
}
fn build_export_function_metadata<Env>( fn build_export_function_metadata<Env>(
env: Env, env: Env,
import_init_function_ptr: for<'a> fn( import_init_function_ptr: for<'a> fn(
@@ -154,6 +178,7 @@ impl Function {
let dynamic_ctx: VMDynamicFunctionContext<DynamicFunctionWithoutEnv> = let dynamic_ctx: VMDynamicFunctionContext<DynamicFunctionWithoutEnv> =
VMDynamicFunctionContext::from_context(DynamicFunctionWithoutEnv { VMDynamicFunctionContext::from_context(DynamicFunctionWithoutEnv {
func: Arc::new(func), func: Arc::new(func),
store: store.clone(),
function_type: ty.clone(), function_type: ty.clone(),
}); });
// We don't yet have the address with the Wasm ABI signature. // We don't yet have the address with the Wasm ABI signature.
@@ -261,6 +286,7 @@ impl Function {
VMDynamicFunctionContext::from_context(DynamicFunctionWithEnv { VMDynamicFunctionContext::from_context(DynamicFunctionWithEnv {
env: Box::new(env), env: Box::new(env),
func: Arc::new(func), func: Arc::new(func),
store: store.clone(),
function_type: ty.clone(), function_type: ty.clone(),
}); });
@@ -546,7 +572,7 @@ impl Function {
for (index, &value_type) in signature.results().iter().enumerate() { for (index, &value_type) in signature.results().iter().enumerate() {
unsafe { unsafe {
let ptr = values_vec.as_ptr().add(index); let ptr = values_vec.as_ptr().add(index);
results[index] = Val::read_value_from(ptr, value_type); results[index] = Val::read_value_from(&self.store, ptr, value_type);
} }
} }
@@ -629,6 +655,7 @@ impl Function {
FunctionDefinition::Wasm(wasm) => { FunctionDefinition::Wasm(wasm) => {
self.call_wasm(&wasm, params, &mut results)?; self.call_wasm(&wasm, params, &mut results)?;
} }
// TODO: we can trivially hit this, look into it
_ => unimplemented!("The function definition isn't supported for the moment"), _ => unimplemented!("The function definition isn't supported for the moment"),
} }
@@ -653,16 +680,14 @@ impl Function {
} }
} }
pub(crate) fn checked_anyfunc(&self) -> VMCallerCheckedAnyfunc { pub(crate) fn vm_funcref(&self) -> VMFuncRef {
let vmsignature = self let engine = self.store.engine();
.store let vmsignature = engine.register_signature(&self.exported.vm_function.signature);
.engine() engine.register_function_metadata(VMCallerCheckedAnyfunc {
.register_signature(&self.exported.vm_function.signature);
VMCallerCheckedAnyfunc {
func_ptr: self.exported.vm_function.address, func_ptr: self.exported.vm_function.address,
type_index: vmsignature, type_index: vmsignature,
vmctx: self.exported.vm_function.vmctx, vmctx: self.exported.vm_function.vmctx,
} })
} }
/// Transform this WebAssembly function into a function with the /// Transform this WebAssembly function into a function with the
@@ -812,6 +837,7 @@ impl fmt::Debug for Function {
pub(crate) trait VMDynamicFunction: Send + Sync { pub(crate) trait VMDynamicFunction: Send + Sync {
fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError>; fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError>;
fn function_type(&self) -> &FunctionType; fn function_type(&self) -> &FunctionType;
fn store(&self) -> &Store;
} }
#[derive(Clone)] #[derive(Clone)]
@@ -819,6 +845,7 @@ pub(crate) struct DynamicFunctionWithoutEnv {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
func: Arc<dyn Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync>, func: Arc<dyn Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync>,
function_type: FunctionType, function_type: FunctionType,
store: Store,
} }
impl VMDynamicFunction for DynamicFunctionWithoutEnv { impl VMDynamicFunction for DynamicFunctionWithoutEnv {
@@ -828,6 +855,9 @@ impl VMDynamicFunction for DynamicFunctionWithoutEnv {
fn function_type(&self) -> &FunctionType { fn function_type(&self) -> &FunctionType {
&self.function_type &self.function_type
} }
fn store(&self) -> &Store {
&self.store
}
} }
pub(crate) struct DynamicFunctionWithEnv<Env> pub(crate) struct DynamicFunctionWithEnv<Env>
@@ -837,6 +867,7 @@ where
function_type: FunctionType, function_type: FunctionType,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
func: Arc<dyn Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync>, func: Arc<dyn Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync>,
store: Store,
env: Box<Env>, env: Box<Env>,
} }
@@ -845,6 +876,7 @@ impl<Env: Sized + Clone + 'static + Send + Sync> Clone for DynamicFunctionWithEn
Self { Self {
env: self.env.clone(), env: self.env.clone(),
function_type: self.function_type.clone(), function_type: self.function_type.clone(),
store: self.store.clone(),
func: self.func.clone(), func: self.func.clone(),
} }
} }
@@ -860,6 +892,9 @@ where
fn function_type(&self) -> &FunctionType { fn function_type(&self) -> &FunctionType {
&self.function_type &self.function_type
} }
fn store(&self) -> &Store {
&self.store
}
} }
trait VMDynamicFunctionCall<T: VMDynamicFunction> { trait VMDynamicFunctionCall<T: VMDynamicFunction> {
@@ -892,8 +927,9 @@ impl<T: VMDynamicFunction> VMDynamicFunctionCall<T> for VMDynamicFunctionContext
let result = panic::catch_unwind(AssertUnwindSafe(|| { let result = panic::catch_unwind(AssertUnwindSafe(|| {
let func_ty = self.ctx.function_type(); let func_ty = self.ctx.function_type();
let mut args = Vec::with_capacity(func_ty.params().len()); let mut args = Vec::with_capacity(func_ty.params().len());
let store = self.ctx.store();
for (i, ty) in func_ty.params().iter().enumerate() { for (i, ty) in func_ty.params().iter().enumerate() {
args.push(Val::read_value_from(values_vec.add(i), *ty)); args.push(Val::read_value_from(store, values_vec.add(i), *ty));
} }
let returns = self.ctx.call(&args)?; let returns = self.ctx.call(&args)?;
@@ -911,7 +947,9 @@ impl<T: VMDynamicFunction> VMDynamicFunctionCall<T> for VMDynamicFunctionContext
ret.write_value_to(values_vec.add(i)); ret.write_value_to(values_vec.add(i));
} }
Ok(()) Ok(())
})); })); // We get extern ref drops at the end of this block that we don't need.
// By preventing extern ref incs in the code above we can save the work of
// incrementing and decrementing. However the logic as-is is correct.
match result { match result {
Ok(Ok(())) => {} Ok(Ok(())) => {}
@@ -929,6 +967,9 @@ mod inner {
use std::error::Error; use std::error::Error;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::panic::{self, AssertUnwindSafe}; use std::panic::{self, AssertUnwindSafe};
#[cfg(feature = "experimental-reference-types-extern-ref")]
pub use wasmer_types::{ExternRef, VMExternRef};
use wasmer_types::{FunctionType, NativeWasmType, Type}; use wasmer_types::{FunctionType, NativeWasmType, Type};
use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody}; use wasmer_vm::{raise_user_trap, resume_panic, VMFunctionBody};
@@ -939,7 +980,7 @@ mod inner {
/// `FromNativeWasmType` and `ToNativeWasmType` but it creates a /// `FromNativeWasmType` and `ToNativeWasmType` but it creates a
/// non-negligible complexity in the `WasmTypeList` /// non-negligible complexity in the `WasmTypeList`
/// implementation. /// implementation.
pub unsafe trait FromToNativeWasmType: Copy pub unsafe trait FromToNativeWasmType
where where
Self: Sized, Self: Sized,
{ {
@@ -1021,6 +1062,18 @@ mod inner {
f64 => f64 f64 => f64
); );
#[cfg(feature = "experimental-reference-types-extern-ref")]
unsafe impl FromToNativeWasmType for ExternRef {
type Native = VMExternRef;
fn to_native(self) -> Self::Native {
self.into()
}
fn from_native(n: Self::Native) -> Self {
n.into()
}
}
#[cfg(test)] #[cfg(test)]
mod test_from_to_native_wasm_type { mod test_from_to_native_wasm_type {
use super::*; use super::*;

View File

@@ -126,7 +126,7 @@ impl Global {
/// assert_eq!(g.get(), Value::I32(1)); /// assert_eq!(g.get(), Value::I32(1));
/// ``` /// ```
pub fn get(&self) -> Val { pub fn get(&self) -> Val {
self.global.get() self.global.get(&self.store)
} }
/// Sets a custom value [`Val`] to the runtime Global. /// Sets a custom value [`Val`] to the runtime Global.

View File

@@ -7,7 +7,7 @@ use crate::TableType;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::sync::Arc; use std::sync::Arc;
use wasmer_engine::{Export, ExportTable}; use wasmer_engine::{Export, ExportTable};
use wasmer_vm::{Table as RuntimeTable, VMCallerCheckedAnyfunc, VMExportTable}; use wasmer_vm::{Table as RuntimeTable, TableElement, VMExportTable};
/// A WebAssembly `table` instance. /// A WebAssembly `table` instance.
/// ///
@@ -27,7 +27,7 @@ pub struct Table {
fn set_table_item( fn set_table_item(
table: &dyn RuntimeTable, table: &dyn RuntimeTable,
item_index: u32, item_index: u32,
item: VMCallerCheckedAnyfunc, item: TableElement,
) -> Result<(), RuntimeError> { ) -> Result<(), RuntimeError> {
table.set(item_index, item).map_err(|e| e.into()) table.set(item_index, item).map_err(|e| e.into())
} }
@@ -40,7 +40,7 @@ impl Table {
/// This function will construct the `Table` using the store /// This function will construct the `Table` using the store
/// [`BaseTunables`][crate::tunables::BaseTunables]. /// [`BaseTunables`][crate::tunables::BaseTunables].
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> { pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
let item = init.into_checked_anyfunc(store)?; let item = init.into_table_reference(store)?;
let tunables = store.tunables(); let tunables = store.tunables();
let style = tunables.table_style(&ty); let style = tunables.table_style(&ty);
let table = tunables let table = tunables
@@ -71,12 +71,12 @@ impl Table {
/// Retrieves an element of the table at the provided `index`. /// Retrieves an element of the table at the provided `index`.
pub fn get(&self, index: u32) -> Option<Val> { pub fn get(&self, index: u32) -> Option<Val> {
let item = self.table.get(index)?; let item = self.table.get(index)?;
Some(ValFuncRef::from_checked_anyfunc(item, &self.store)) Some(ValFuncRef::from_table_reference(item, &self.store))
} }
/// Sets an element `val` in the Table at the provided `index`. /// Sets an element `val` in the Table at the provided `index`.
pub fn set(&self, index: u32, val: Val) -> Result<(), RuntimeError> { pub fn set(&self, index: u32, val: Val) -> Result<(), RuntimeError> {
let item = val.into_checked_anyfunc(&self.store)?; let item = val.into_table_reference(&self.store)?;
set_table_item(self.table.as_ref(), index, item) set_table_item(self.table.as_ref(), index, item)
} }
@@ -95,19 +95,10 @@ impl Table {
/// ///
/// Returns an error if the `delta` is out of bounds for the table. /// Returns an error if the `delta` is out of bounds for the table.
pub fn grow(&self, delta: u32, init: Val) -> Result<u32, RuntimeError> { pub fn grow(&self, delta: u32, init: Val) -> Result<u32, RuntimeError> {
let item = init.into_checked_anyfunc(&self.store)?; let item = init.into_table_reference(&self.store)?;
match self.table.grow(delta) { self.table
Some(len) => { .grow(delta, item)
for i in 0..delta { .ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{}`", delta)))
set_table_item(self.table.as_ref(), len + i, item.clone())?;
}
Ok(len)
}
None => Err(RuntimeError::new(format!(
"failed to grow table by `{}`",
delta
))),
}
} }
/// Copies the `len` elements of `src_table` starting at `src_index` /// Copies the `len` elements of `src_table` starting at `src_index`

View File

@@ -296,8 +296,8 @@ pub use crate::ptr::{Array, Item, WasmPtr};
pub use crate::store::{Store, StoreObject}; pub use crate::store::{Store, StoreObject};
pub use crate::tunables::BaseTunables; pub use crate::tunables::BaseTunables;
pub use crate::types::{ pub use crate::types::{
ExportType, ExternRef, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType, ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
MemoryType, Mutability, TableType, Val, ValType, TableType, Val, ValType,
}; };
pub use crate::types::{Val as Value, ValType as Type}; pub use crate::types::{Val as Value, ValType as Type};
pub use crate::utils::is_wasm; pub use crate::utils::is_wasm;
@@ -314,6 +314,8 @@ pub use wasmer_engine::{
ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver, ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver,
NamedResolverChain, Resolver, RuntimeError, SerializeError, Tunables, NamedResolverChain, Resolver, RuntimeError, SerializeError, Tunables,
}; };
#[cfg(feature = "experimental-reference-types-extern-ref")]
pub use wasmer_types::ExternRef;
pub use wasmer_types::{ pub use wasmer_types::{
Atomically, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType, Atomically, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,

View File

@@ -1,12 +1,12 @@
use crate::externals::Function; use crate::externals::Function;
use crate::store::{Store, StoreObject}; use crate::store::{Store, StoreObject};
use crate::RuntimeError; use crate::RuntimeError;
use std::ptr;
use wasmer_types::Value; use wasmer_types::Value;
pub use wasmer_types::{ pub use wasmer_types::{
ExportType, ExternRef, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType, ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
MemoryType, Mutability, TableType, Type as ValType, TableType, Type as ValType,
}; };
use wasmer_vm::VMFuncRef;
/// WebAssembly computations manipulate values of basic value types: /// WebAssembly computations manipulate values of basic value types:
/// * Integers (32 or 64 bit width) /// * Integers (32 or 64 bit width)
@@ -19,9 +19,10 @@ pub type Val = Value<Function>;
impl StoreObject for Val { impl StoreObject for Val {
fn comes_from_same_store(&self, store: &Store) -> bool { fn comes_from_same_store(&self, store: &Store) -> bool {
match self { match self {
Self::FuncRef(f) => Store::same(store, f.store()), Self::FuncRef(None) => true,
Self::ExternRef(ExternRef::Ref(_)) | Self::ExternRef(ExternRef::Other(_)) => false, Self::FuncRef(Some(f)) => Store::same(store, f.store()),
Self::ExternRef(ExternRef::Null) => true, // `ExternRef`s are not tied to specific stores
Self::ExternRef(_) => true,
Self::I32(_) | Self::I64(_) | Self::F32(_) | Self::F64(_) | Self::V128(_) => true, Self::I32(_) | Self::I64(_) | Self::F32(_) | Self::F64(_) | Self::V128(_) => true,
} }
} }
@@ -29,46 +30,42 @@ impl StoreObject for Val {
impl From<Function> for Val { impl From<Function> for Val {
fn from(val: Function) -> Self { fn from(val: Function) -> Self {
Self::FuncRef(val) Self::FuncRef(Some(val))
} }
} }
/// It provides useful functions for converting back and forth /// It provides useful functions for converting back and forth
/// from [`Val`] into `FuncRef`. /// from [`Val`] into `FuncRef`.
pub trait ValFuncRef { pub trait ValFuncRef {
fn into_checked_anyfunc( fn into_vm_funcref(&self, store: &Store) -> Result<VMFuncRef, RuntimeError>;
&self,
store: &Store,
) -> Result<wasmer_vm::VMCallerCheckedAnyfunc, RuntimeError>;
fn from_checked_anyfunc(item: wasmer_vm::VMCallerCheckedAnyfunc, store: &Store) -> Self; fn from_vm_funcref(item: VMFuncRef, store: &Store) -> Self;
fn into_table_reference(&self, store: &Store) -> Result<wasmer_vm::TableElement, RuntimeError>;
fn from_table_reference(item: wasmer_vm::TableElement, store: &Store) -> Self;
} }
impl ValFuncRef for Val { impl ValFuncRef for Val {
fn into_checked_anyfunc( fn into_vm_funcref(&self, store: &Store) -> Result<VMFuncRef, RuntimeError> {
&self,
store: &Store,
) -> Result<wasmer_vm::VMCallerCheckedAnyfunc, RuntimeError> {
if !self.comes_from_same_store(store) { if !self.comes_from_same_store(store) {
return Err(RuntimeError::new("cross-`Store` values are not supported")); return Err(RuntimeError::new("cross-`Store` values are not supported"));
} }
Ok(match self { Ok(match self {
Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc { Self::FuncRef(None) => VMFuncRef::null(),
func_ptr: ptr::null(), Self::FuncRef(Some(f)) => f.vm_funcref(),
type_index: wasmer_vm::VMSharedSignatureIndex::default(), _ => return Err(RuntimeError::new("val is not func ref")),
vmctx: wasmer_vm::VMFunctionEnvironment {
host_env: ptr::null_mut(),
},
},
Self::FuncRef(f) => f.checked_anyfunc(),
_ => return Err(RuntimeError::new("val is not funcref")),
}) })
} }
fn from_checked_anyfunc(item: wasmer_vm::VMCallerCheckedAnyfunc, store: &Store) -> Self { fn from_vm_funcref(func_ref: VMFuncRef, store: &Store) -> Self {
if item.type_index == wasmer_vm::VMSharedSignatureIndex::default() { if func_ref.is_null() {
return Self::ExternRef(ExternRef::Null); return Self::FuncRef(None);
} }
let item: &wasmer_vm::VMCallerCheckedAnyfunc = unsafe {
let anyfunc: *const wasmer_vm::VMCallerCheckedAnyfunc = *func_ref;
&*anyfunc
};
let signature = store let signature = store
.engine() .engine()
.lookup_signature(item.type_index) .lookup_signature(item.type_index)
@@ -80,6 +77,7 @@ impl ValFuncRef for Val {
vm_function: wasmer_vm::VMExportFunction { vm_function: wasmer_vm::VMExportFunction {
address: item.func_ptr, address: item.func_ptr,
signature, signature,
// TODO: review this comment (unclear if it's still correct):
// All functions in tables are already Static (as dynamic functions // All functions in tables are already Static (as dynamic functions
// are converted to use the trampolines with static signatures). // are converted to use the trampolines with static signatures).
kind: wasmer_vm::VMFunctionKind::Static, kind: wasmer_vm::VMFunctionKind::Static,
@@ -89,6 +87,28 @@ impl ValFuncRef for Val {
}, },
}; };
let f = Function::from_vm_export(store, export); let f = Function::from_vm_export(store, export);
Self::FuncRef(f) Self::FuncRef(Some(f))
}
fn into_table_reference(&self, store: &Store) -> Result<wasmer_vm::TableElement, RuntimeError> {
if !self.comes_from_same_store(store) {
return Err(RuntimeError::new("cross-`Store` values are not supported"));
}
Ok(match self {
// TODO(reftypes): review this clone
Self::ExternRef(extern_ref) => {
wasmer_vm::TableElement::ExternRef(extern_ref.clone().into())
}
Self::FuncRef(None) => wasmer_vm::TableElement::FuncRef(VMFuncRef::null()),
Self::FuncRef(Some(f)) => wasmer_vm::TableElement::FuncRef(f.vm_funcref()),
_ => return Err(RuntimeError::new("val is not reference")),
})
}
fn from_table_reference(item: wasmer_vm::TableElement, store: &Store) -> Self {
match item {
wasmer_vm::TableElement::FuncRef(f) => Self::from_vm_funcref(f, store),
wasmer_vm::TableElement::ExternRef(extern_ref) => Self::ExternRef(extern_ref.into()),
}
} }
} }

View File

@@ -67,7 +67,7 @@ fn table_new() -> Result<()> {
maximum: None, maximum: None,
}; };
let f = Function::new_native(&store, || {}); let f = Function::new_native(&store, || {});
let table = Table::new(&store, table_type, Value::FuncRef(f))?; let table = Table::new(&store, table_type, Value::FuncRef(Some(f)))?;
assert_eq!(*table.ty(), table_type); assert_eq!(*table.ty(), table_type);
// Anyrefs not yet supported // Anyrefs not yet supported
@@ -92,7 +92,7 @@ fn table_get() -> Result<()> {
maximum: Some(1), maximum: Some(1),
}; };
let f = Function::new_native(&store, |num: i32| num + 1); let f = Function::new_native(&store, |num: i32| num + 1);
let table = Table::new(&store, table_type, Value::FuncRef(f.clone()))?; let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
assert_eq!(*table.ty(), table_type); assert_eq!(*table.ty(), table_type);
let _elem = table.get(0).unwrap(); let _elem = table.get(0).unwrap();
// assert_eq!(elem.funcref().unwrap(), f); // assert_eq!(elem.funcref().unwrap(), f);
@@ -115,13 +115,13 @@ fn table_grow() -> Result<()> {
maximum: Some(10), maximum: Some(10),
}; };
let f = Function::new_native(&store, |num: i32| num + 1); let f = Function::new_native(&store, |num: i32| num + 1);
let table = Table::new(&store, table_type, Value::FuncRef(f.clone()))?; let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
// Growing to a bigger maximum should return None // Growing to a bigger maximum should return None
let old_len = table.grow(12, Value::FuncRef(f.clone())); let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
assert!(old_len.is_err()); assert!(old_len.is_err());
// Growing to a bigger maximum should return None // Growing to a bigger maximum should return None
let old_len = table.grow(5, Value::FuncRef(f.clone()))?; let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
assert_eq!(old_len, 0); assert_eq!(old_len, 0);
Ok(()) Ok(())

View File

@@ -0,0 +1,497 @@
use anyhow::Result;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use wasmer::*;
#[test]
fn func_ref_passed_and_returned() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(import "env" "func_ref_identity" (func (param funcref) (result funcref)))
(type $ret_i32_ty (func (result i32)))
(table $table (export "table") 2 2 funcref)
(func (export "run") (param) (result funcref)
(call 0 (ref.null func)))
(func (export "call_set_value") (param $fr funcref) (result i32)
(table.set $table (i32.const 0) (local.get $fr))
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
)"#;
let module = Module::new(&store, wat)?;
let imports = imports! {
"env" => {
"func_ref_identity" => Function::new(&store, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |values| -> Result<Vec<_>, _> {
Ok(vec![values[0].clone()])
})
},
};
let instance = Instance::new(&module, &imports)?;
let f: &Function = instance.exports.get_function("run")?;
let results = f.call(&[]).unwrap();
if let Value::FuncRef(fr) = &results[0] {
assert!(fr.is_none());
} else {
panic!("funcref not found!");
}
#[derive(Clone, Debug, WasmerEnv)]
pub struct Env(Arc<AtomicBool>);
let env = Env(Arc::new(AtomicBool::new(false)));
let func_to_call = Function::new_native_with_env(&store, env.clone(), |env: &Env| -> i32 {
env.0.store(true, Ordering::SeqCst);
343
});
let call_set_value: &Function = instance.exports.get_function("call_set_value")?;
let results: Box<[Value]> = call_set_value.call(&[Value::FuncRef(Some(func_to_call))])?;
assert!(env.0.load(Ordering::SeqCst));
assert_eq!(&*results, &[Value::I32(343)]);
Ok(())
}
#[test]
fn func_ref_passed_and_called() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(func $func_ref_call (import "env" "func_ref_call") (param funcref) (result i32))
(type $ret_i32_ty (func (result i32)))
(table $table (export "table") 2 2 funcref)
(func $product (param $x i32) (param $y i32) (result i32)
(i32.mul (local.get $x) (local.get $y)))
;; TODO: figure out exactly why this statement is needed
(elem declare func $product)
(func (export "call_set_value") (param $fr funcref) (result i32)
(table.set $table (i32.const 0) (local.get $fr))
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
(func (export "call_func") (param $fr funcref) (result i32)
(call $func_ref_call (local.get $fr)))
(func (export "call_host_func_with_wasm_func") (result i32)
(call $func_ref_call (ref.func $product)))
)"#;
let module = Module::new(&store, wat)?;
fn func_ref_call(values: &[Value]) -> Result<Vec<Value>, RuntimeError> {
// TODO: look into `Box<[Value]>` being returned breakage
let f = values[0].unwrap_funcref().as_ref().unwrap();
let f: NativeFunc<(i32, i32), i32> = f.native()?;
Ok(vec![Value::I32(f.call(7, 9)?)])
}
let imports = imports! {
"env" => {
"func_ref_call" => Function::new(
&store,
FunctionType::new([Type::FuncRef], [Type::I32]),
func_ref_call
),
// TODO(reftypes): this should work
/*
"func_ref_call_native" => Function::new_native(&store, |f: Function| -> Result<i32, RuntimeError> {
let f: NativeFunc::<(i32, i32), i32> = f.native()?;
f.call(7, 9)
})
*/
},
};
let instance = Instance::new(&module, &imports)?;
{
fn sum(a: i32, b: i32) -> i32 {
a + b
}
let sum_func = Function::new_native(&store, sum);
let call_func: &Function = instance.exports.get_function("call_func")?;
let result = call_func.call(&[Value::FuncRef(Some(sum_func))])?;
assert_eq!(result[0].unwrap_i32(), 16);
}
{
let f: NativeFunc<(), i32> = instance
.exports
.get_native_function("call_host_func_with_wasm_func")?;
let result = f.call()?;
assert_eq!(result, 63);
}
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
fn extern_ref_passed_and_returned() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(func $extern_ref_identity (import "env" "extern_ref_identity") (param externref) (result externref))
(func $extern_ref_identity_native (import "env" "extern_ref_identity_native") (param externref) (result externref))
(func $get_new_extern_ref (import "env" "get_new_extern_ref") (result externref))
(func $get_new_extern_ref_native (import "env" "get_new_extern_ref_native") (result externref))
(func (export "run") (param) (result externref)
(call $extern_ref_identity (ref.null extern)))
(func (export "run_native") (param) (result externref)
(call $extern_ref_identity_native (ref.null extern)))
(func (export "get_hashmap") (param) (result externref)
(call $get_new_extern_ref))
(func (export "get_hashmap_native") (param) (result externref)
(call $get_new_extern_ref_native))
)"#;
let module = Module::new(&store, wat)?;
let imports = imports! {
"env" => {
"extern_ref_identity" => Function::new(&store, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |values| -> Result<Vec<_>, _> {
Ok(vec![values[0].clone()])
}),
"extern_ref_identity_native" => Function::new_native(&store, |er: ExternRef| -> ExternRef {
er
}),
"get_new_extern_ref" => Function::new(&store, FunctionType::new([], [Type::ExternRef]), |_| -> Result<Vec<_>, _> {
let inner =
[("hello".to_string(), "world".to_string()),
("color".to_string(), "orange".to_string())]
.iter()
.cloned()
.collect::<HashMap<String, String>>();
let new_extern_ref = ExternRef::new(inner);
Ok(vec![Value::ExternRef(new_extern_ref)])
}),
"get_new_extern_ref_native" => Function::new_native(&store, || -> ExternRef {
let inner =
[("hello".to_string(), "world".to_string()),
("color".to_string(), "orange".to_string())]
.iter()
.cloned()
.collect::<HashMap<String, String>>();
ExternRef::new(inner)
})
},
};
let instance = Instance::new(&module, &imports)?;
for run in &["run", "run_native"] {
let f: &Function = instance.exports.get_function(run)?;
let results = f.call(&[]).unwrap();
if let Value::ExternRef(er) = &results[0] {
assert!(er.is_null());
} else {
panic!("result is not an extern ref!");
}
let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(run)?;
let result: ExternRef = f.call()?;
assert!(result.is_null());
}
for get_hashmap in &["get_hashmap", "get_hashmap_native"] {
let f: &Function = instance.exports.get_function(get_hashmap)?;
let results = f.call(&[]).unwrap();
if let Value::ExternRef(er) = &results[0] {
let inner: &HashMap<String, String> = er.downcast().unwrap();
assert_eq!(inner["hello"], "world");
assert_eq!(inner["color"], "orange");
} else {
panic!("result is not an extern ref!");
}
let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(get_hashmap)?;
let result: ExternRef = f.call()?;
let inner: &HashMap<String, String> = result.downcast().unwrap();
assert_eq!(inner["hello"], "world");
assert_eq!(inner["color"], "orange");
}
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
// TODO(reftypes): reenable this test
#[ignore]
fn extern_ref_ref_counting_basic() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(func (export "drop") (param $er externref) (result)
(drop (local.get $er)))
)"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let f: NativeFunc<ExternRef, ()> = instance.exports.get_native_function("drop")?;
let er = ExternRef::new(3u32);
f.call(er.clone())?;
assert_eq!(er.downcast::<u32>().unwrap(), &3);
assert_eq!(er.strong_count(), 1);
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
fn refs_in_globals() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(global $er_global (export "er_global") (mut externref) (ref.null extern))
(global $fr_global (export "fr_global") (mut funcref) (ref.null func))
(global $fr_immutable_global (export "fr_immutable_global") funcref (ref.func $hello))
(func $hello (param) (result i32)
(i32.const 73))
)"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
{
let er_global: &Global = instance.exports.get_global("er_global")?;
if let Value::ExternRef(er) = er_global.get() {
assert!(er.is_null());
} else {
panic!("Did not find extern ref in the global");
}
er_global.set(Val::ExternRef(ExternRef::new(3u32)))?;
if let Value::ExternRef(er) = er_global.get() {
assert_eq!(er.downcast::<u32>().unwrap(), &3);
assert_eq!(er.strong_count(), 1);
} else {
panic!("Did not find extern ref in the global");
}
}
{
let fr_global: &Global = instance.exports.get_global("fr_immutable_global")?;
if let Value::FuncRef(Some(f)) = fr_global.get() {
let native_func: NativeFunc<(), u32> = f.native()?;
assert_eq!(native_func.call()?, 73);
} else {
panic!("Did not find non-null func ref in the global");
}
}
{
let fr_global: &Global = instance.exports.get_global("fr_global")?;
if let Value::FuncRef(None) = fr_global.get() {
} else {
panic!("Did not find a null func ref in the global");
}
let f = Function::new_native(&store, |arg1: i32, arg2: i32| -> i32 { arg1 + arg2 });
fr_global.set(Val::FuncRef(Some(f)))?;
if let Value::FuncRef(Some(f)) = fr_global.get() {
let native: NativeFunc<(i32, i32), i32> = f.native()?;
assert_eq!(native.call(5, 7)?, 12);
} else {
panic!("Did not find extern ref in the global");
}
}
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
fn extern_ref_ref_counting_table_basic() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(global $global (export "global") (mut externref) (ref.null extern))
(table $table (export "table") 4 4 externref)
(func $insert (param $er externref) (param $idx i32)
(table.set $table (local.get $idx) (local.get $er)))
(func $intermediate (param $er externref) (param $idx i32)
(call $insert (local.get $er) (local.get $idx)))
(func $insert_into_table (export "insert_into_table") (param $er externref) (param $idx i32) (result externref)
(call $intermediate (local.get $er) (local.get $idx))
(local.get $er))
)"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let f: NativeFunc<(ExternRef, i32), ExternRef> =
instance.exports.get_native_function("insert_into_table")?;
let er = ExternRef::new(3usize);
let er = f.call(er, 1)?;
assert_eq!(er.strong_count(), 2);
let table: &Table = instance.exports.get_table("table")?;
{
let er2 = table.get(1).unwrap().externref().unwrap();
assert_eq!(er2.strong_count(), 3);
}
assert_eq!(er.strong_count(), 2);
table.set(1, Val::ExternRef(ExternRef::null()))?;
assert_eq!(er.strong_count(), 1);
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
// TODO(reftypes): reenable this test
#[ignore]
fn extern_ref_ref_counting_global_basic() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(global $global (export "global") (mut externref) (ref.null extern))
(func $get_from_global (export "get_from_global") (result externref)
(drop (global.get $global))
(global.get $global))
)"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let global: &Global = instance.exports.get_global("global")?;
{
let er = ExternRef::new(3usize);
global.set(Val::ExternRef(er.clone()))?;
assert_eq!(er.strong_count(), 2);
}
let get_from_global: NativeFunc<(), ExternRef> =
instance.exports.get_native_function("get_from_global")?;
let er = get_from_global.call()?;
assert_eq!(er.strong_count(), 2);
global.set(Val::ExternRef(ExternRef::null()))?;
assert_eq!(er.strong_count(), 1);
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
// TODO(reftypes): reenable this test
#[ignore]
fn extern_ref_ref_counting_traps() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(func $pass_er (export "pass_extern_ref") (param externref)
(local.get 0)
(unreachable))
)"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let pass_extern_ref: NativeFunc<ExternRef, ()> =
instance.exports.get_native_function("pass_extern_ref")?;
let er = ExternRef::new(3usize);
assert_eq!(er.strong_count(), 1);
let result = pass_extern_ref.call(er.clone());
assert!(result.is_err());
assert_eq!(er.strong_count(), 1);
Ok(())
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
#[test]
fn extern_ref_ref_counting_table_instructions() -> Result<()> {
let store = Store::default();
let wat = r#"(module
(table $table1 (export "table1") 2 12 externref)
(table $table2 (export "table2") 6 12 externref)
(func $grow_table_with_ref (export "grow_table_with_ref") (param $er externref) (param $size i32) (result i32)
(table.grow $table1 (local.get $er) (local.get $size)))
(func $fill_table_with_ref (export "fill_table_with_ref") (param $er externref) (param $start i32) (param $end i32)
(table.fill $table1 (local.get $start) (local.get $er) (local.get $end)))
(func $copy_into_table2 (export "copy_into_table2")
(table.copy $table2 $table1 (i32.const 0) (i32.const 0) (i32.const 4)))
)"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let grow_table_with_ref: NativeFunc<(ExternRef, i32), i32> = instance
.exports
.get_native_function("grow_table_with_ref")?;
let fill_table_with_ref: NativeFunc<(ExternRef, i32, i32), ()> = instance
.exports
.get_native_function("fill_table_with_ref")?;
let copy_into_table2: NativeFunc<(), ()> =
instance.exports.get_native_function("copy_into_table2")?;
let table1: &Table = instance.exports.get_table("table1")?;
let table2: &Table = instance.exports.get_table("table2")?;
let er1 = ExternRef::new(3usize);
let er2 = ExternRef::new(5usize);
let er3 = ExternRef::new(7usize);
{
let result = grow_table_with_ref.call(er1.clone(), 0)?;
assert_eq!(result, 2);
assert_eq!(er1.strong_count(), 1);
let result = grow_table_with_ref.call(er1.clone(), 10_000)?;
assert_eq!(result, -1);
assert_eq!(er1.strong_count(), 1);
let result = grow_table_with_ref.call(er1.clone(), 8)?;
assert_eq!(result, 2);
assert_eq!(er1.strong_count(), 9);
for i in 2..10 {
let e = table1.get(i).unwrap().unwrap_externref();
assert_eq!(*e.downcast::<usize>().unwrap(), 3);
assert_eq!(&e, &er1);
}
assert_eq!(er1.strong_count(), 9);
}
{
fill_table_with_ref.call(er2.clone(), 0, 2)?;
assert_eq!(er2.strong_count(), 3);
}
{
table2.set(0, Val::ExternRef(er3.clone()))?;
table2.set(1, Val::ExternRef(er3.clone()))?;
table2.set(2, Val::ExternRef(er3.clone()))?;
table2.set(3, Val::ExternRef(er3.clone()))?;
table2.set(4, Val::ExternRef(er3.clone()))?;
assert_eq!(er3.strong_count(), 6);
}
{
copy_into_table2.call()?;
assert_eq!(er3.strong_count(), 2);
assert_eq!(er2.strong_count(), 5);
assert_eq!(er1.strong_count(), 11);
for i in 1..5 {
let e = table2.get(i).unwrap().unwrap_externref();
let value = e.downcast::<usize>().unwrap();
match i {
0 | 1 => assert_eq!(*value, 5),
4 => assert_eq!(*value, 7),
_ => assert_eq!(*value, 3),
}
}
}
{
for i in 0..table1.size() {
table1.set(i, Val::ExternRef(ExternRef::null()))?;
}
for i in 0..table2.size() {
table2.set(i, Val::ExternRef(ExternRef::null()))?;
}
}
assert_eq!(er1.strong_count(), 1);
assert_eq!(er2.strong_count(), 1);
assert_eq!(er3.strong_count(), 1);
Ok(())
}

22
lib/c-api/CHANGELOG.md Normal file
View File

@@ -0,0 +1,22 @@
# C API Changelog
*The format is based on [Keep a Changelog].*
[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/
Looking for changes to the Wasmer CLI and the Rust API? See our [Primary Changelog](../../CHANGELOG.md)
## **[Unreleased]**
### Added
- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Add a new CHANGELOG.md specific to our C API to make it easier for users primarily consuming our C API to keep up to date with changes that affect them.
### Changed
### Fixed
- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Fix ownership in Wasm C API of `wasm_extern_as_func`, `wasm_extern_as_memory`, `wasm_extern_as_table`, `wasm_extern_as_global`, `wasm_func_as_extern`, `wasm_memory_as_extern`, `wasm_table_as_extern`, and `wasm_global_as_extern`. These functions no longer allocate memory and thus their results should not be freed. This is a breaking change to align more closely with the Wasm C API's stated ownership.
## Changes before 2020-04-06
See the [Primary Changelog](../../CHANGELOG.md).

View File

@@ -38,6 +38,7 @@ typetag = { version = "0.1", optional = true }
paste = "1.0" paste = "1.0"
[dev-dependencies] [dev-dependencies]
field-offset = "0.3.3"
inline-c = "0.1.5" inline-c = "0.1.5"
[features] [features]
@@ -53,7 +54,7 @@ wat = ["wasmer/wat"]
wasi = ["wasmer-wasi", "typetag", "serde"] wasi = ["wasmer-wasi", "typetag", "serde"]
engine = [] engine = []
middlewares = ["wasmer-middlewares"] middlewares = ["wasmer-middlewares"]
deprecated = ["libffi"] deprecated = ["libffi", "wasmer/experimental-reference-types-extern-ref"]
jit = [ jit = [
"wasmer-engine-jit", "wasmer-engine-jit",
"engine", "engine",

View File

@@ -77,7 +77,6 @@ int main(int argc, const char* argv[]) {
printf("Results of `sum`: %d\n", results_val[0].of.i32); printf("Results of `sum`: %d\n", results_val[0].of.i32);
wasm_func_delete(sum_func);
wasm_module_delete(module); wasm_module_delete(module);
wasm_instance_delete(instance); wasm_instance_delete(instance);
wasm_extern_vec_delete(&exports); wasm_extern_vec_delete(&exports);

View File

@@ -109,8 +109,6 @@ int main(int argc, const char* argv[]) {
wasm_global_set(some, &some_set_value); wasm_global_set(some, &some_set_value);
printf("`some` value: %.1f\n", some_value.of.f32); printf("`some` value: %.1f\n", some_value.of.f32);
wasm_global_delete(some);
wasm_global_delete(one);
wasm_module_delete(module); wasm_module_delete(module);
wasm_extern_vec_delete(&exports); wasm_extern_vec_delete(&exports);
wasm_instance_delete(instance); wasm_instance_delete(instance);

View File

@@ -124,10 +124,6 @@ int main(int argc, const char* argv[]) {
printf("Got the exported memory: %p\n", memory); printf("Got the exported memory: %p\n", memory);
wasm_func_delete(func);
wasm_global_delete(global);
wasm_table_delete(table);
wasm_memory_delete(memory);
wasm_module_delete(module); wasm_module_delete(module);
wasm_extern_vec_delete(&exports); wasm_extern_vec_delete(&exports);
wasm_instance_delete(instance); wasm_instance_delete(instance);

View File

@@ -99,10 +99,6 @@ int main(int argc, const char* argv[]) {
printf("Value at 0x%04x: %d\n", mem_addr, get_at_results_val[0].of.i32); printf("Value at 0x%04x: %d\n", mem_addr, get_at_results_val[0].of.i32);
wasm_memory_delete(memory);
wasm_func_delete(mem_size);
wasm_func_delete(set_at);
wasm_func_delete(get_at);
wasm_extern_vec_delete(&exports); wasm_extern_vec_delete(&exports);
wasm_module_delete(module); wasm_module_delete(module);
wasm_instance_delete(instance); wasm_instance_delete(instance);

View File

@@ -18,7 +18,7 @@ fn get_default_table_value(table_type: ValType) -> Val {
ValType::F64 => Val::F64(0.), ValType::F64 => Val::F64(0.),
ValType::V128 => Val::V128(0), ValType::V128 => Val::V128(0),
ValType::ExternRef => Val::ExternRef(ExternRef::null()), ValType::ExternRef => Val::ExternRef(ExternRef::null()),
ValType::FuncRef => Val::ExternRef(ExternRef::null()), ValType::FuncRef => Val::FuncRef(None),
} }
} }

View File

@@ -2,17 +2,27 @@ use super::super::store::wasm_store_t;
use super::super::trap::wasm_trap_t; use super::super::trap::wasm_trap_t;
use super::super::types::{wasm_functype_t, wasm_valkind_enum}; use super::super::types::{wasm_functype_t, wasm_valkind_enum};
use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t}; use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
use super::CApiExternTag;
use std::convert::TryInto; use std::convert::TryInto;
use std::ffi::c_void; use std::ffi::c_void;
use std::sync::Arc; use std::sync::Arc;
use wasmer::{Function, Instance, RuntimeError, Val}; use wasmer::{Function, RuntimeError, Val};
#[derive(Debug)] #[derive(Debug, Clone)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)]
pub struct wasm_func_t { pub struct wasm_func_t {
pub(crate) inner: Function, pub(crate) tag: CApiExternTag,
// this is how we ensure the instance stays alive pub(crate) inner: Box<Function>,
pub(crate) instance: Option<Arc<Instance>>, }
impl wasm_func_t {
pub(crate) fn new(function: Function) -> Self {
Self {
tag: CApiExternTag::Function,
inner: Box::new(function),
}
}
} }
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@@ -80,10 +90,7 @@ pub unsafe extern "C" fn wasm_func_new(
}; };
let function = Function::new(&store.inner, func_sig, inner_callback); let function = Function::new(&store.inner, func_sig, inner_callback);
Some(Box::new(wasm_func_t { Some(Box::new(wasm_func_t::new(function)))
instance: None,
inner: function,
}))
} }
#[no_mangle] #[no_mangle]
@@ -115,9 +122,8 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
impl Drop for WrapperEnv { impl Drop for WrapperEnv {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(env_finalizer) = Arc::get_mut(&mut self.env_finalizer) if let Some(env_finalizer) =
.map(Option::take) Arc::get_mut(&mut self.env_finalizer).and_then(Option::take)
.flatten()
{ {
if !self.env.is_null() { if !self.env.is_null() {
unsafe { (env_finalizer)(self.env as _) } unsafe { (env_finalizer)(self.env as _) }
@@ -172,10 +178,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
trampoline, trampoline,
); );
Some(Box::new(wasm_func_t { Some(Box::new(wasm_func_t::new(function)))
instance: None,
inner: function,
}))
} }
#[no_mangle] #[no_mangle]

View File

@@ -1,14 +1,26 @@
use super::super::store::wasm_store_t; use super::super::store::wasm_store_t;
use super::super::types::wasm_globaltype_t; use super::super::types::wasm_globaltype_t;
use super::super::value::wasm_val_t; use super::super::value::wasm_val_t;
use super::CApiExternTag;
use crate::error::update_last_error; use crate::error::update_last_error;
use std::convert::TryInto; use std::convert::TryInto;
use wasmer::{Global, Val}; use wasmer::{Global, Val};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Clone, Debug)]
pub struct wasm_global_t { pub struct wasm_global_t {
// maybe needs to hold onto instance pub(crate) tag: CApiExternTag,
pub(crate) inner: Global, pub(crate) inner: Box<Global>,
}
impl wasm_global_t {
pub(crate) fn new(global: Global) -> Self {
Self {
tag: CApiExternTag::Global,
inner: Box::new(global),
}
}
} }
#[no_mangle] #[no_mangle]
@@ -30,7 +42,7 @@ pub unsafe extern "C" fn wasm_global_new(
Global::new(store, wasm_val) Global::new(store, wasm_val)
}; };
Some(Box::new(wasm_global_t { inner: global })) Some(Box::new(wasm_global_t::new(global)))
} }
#[no_mangle] #[no_mangle]
@@ -40,9 +52,7 @@ pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>)
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> { pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> {
// do shallow copy // do shallow copy
Box::new(wasm_global_t { Box::new(wasm_global_t::new((&*global.inner).clone()))
inner: global.inner.clone(),
})
} }
#[no_mangle] #[no_mangle]

View File

@@ -1,12 +1,24 @@
use super::super::store::wasm_store_t; use super::super::store::wasm_store_t;
use super::super::types::wasm_memorytype_t; use super::super::types::wasm_memorytype_t;
use super::CApiExternTag;
use std::mem; use std::mem;
use wasmer::{Memory, Pages}; use wasmer::{Memory, Pages};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Clone, Debug)]
pub struct wasm_memory_t { pub struct wasm_memory_t {
// maybe needs to hold onto instance pub(crate) tag: CApiExternTag,
pub(crate) inner: Memory, pub(crate) inner: Box<Memory>,
}
impl wasm_memory_t {
pub(crate) fn new(memory: Memory) -> Self {
Self {
tag: CApiExternTag::Memory,
inner: Box::new(memory),
}
}
} }
#[no_mangle] #[no_mangle]
@@ -20,7 +32,7 @@ pub unsafe extern "C" fn wasm_memory_new(
let memory_type = memory_type.inner().memory_type.clone(); let memory_type = memory_type.inner().memory_type.clone();
let memory = c_try!(Memory::new(&store.inner, memory_type)); let memory = c_try!(Memory::new(&store.inner, memory_type));
Some(Box::new(wasm_memory_t { inner: memory })) Some(Box::new(wasm_memory_t::new(memory)))
} }
#[no_mangle] #[no_mangle]
@@ -30,9 +42,7 @@ pub unsafe extern "C" fn wasm_memory_delete(_memory: Option<Box<wasm_memory_t>>)
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> { pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> {
// do shallow copy // do shallow copy
Box::new(wasm_memory_t { Box::new(wasm_memory_t::new((&*memory.inner).clone()))
inner: memory.inner.clone(),
})
} }
#[no_mangle] #[no_mangle]

View File

@@ -6,16 +6,167 @@ mod table;
pub use function::*; pub use function::*;
pub use global::*; pub use global::*;
pub use memory::*; pub use memory::*;
use std::sync::Arc; use std::mem;
pub use table::*; pub use table::*;
use wasmer::{Extern, Instance}; use wasmer::{Extern, ExternType};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[repr(transparent)]
pub struct wasm_extern_t { pub struct wasm_extern_t {
// this is how we ensure the instance stays alive pub(crate) inner: wasm_extern_inner,
pub(crate) instance: Option<Arc<Instance>>, }
pub(crate) inner: Extern,
/// All elements in this union must be `repr(C)` and have a
/// `CApiExternTag` as their first element.
#[allow(non_camel_case_types)]
pub(crate) union wasm_extern_inner {
function: mem::ManuallyDrop<wasm_func_t>,
memory: mem::ManuallyDrop<wasm_memory_t>,
global: mem::ManuallyDrop<wasm_global_t>,
table: mem::ManuallyDrop<wasm_table_t>,
}
#[cfg(test)]
mod extern_tests {
use super::*;
#[test]
fn externs_are_the_same_size() {
use std::mem::{align_of, size_of};
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_func_t>());
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_memory_t>());
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_global_t>());
assert_eq!(size_of::<wasm_extern_t>(), size_of::<wasm_table_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_func_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_memory_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_global_t>());
assert_eq!(align_of::<wasm_extern_t>(), align_of::<wasm_table_t>());
}
#[test]
fn tags_are_the_same_offset_away() {
use field_offset::offset_of;
let func_tag_offset = offset_of!(wasm_func_t => tag).get_byte_offset();
let memory_tag_offset = offset_of!(wasm_memory_t => tag).get_byte_offset();
let global_tag_offset = offset_of!(wasm_global_t => tag).get_byte_offset();
let table_tag_offset = offset_of!(wasm_table_t => tag).get_byte_offset();
assert_eq!(func_tag_offset, memory_tag_offset);
assert_eq!(global_tag_offset, table_tag_offset);
assert_eq!(func_tag_offset, global_tag_offset);
}
}
impl Drop for wasm_extern_inner {
fn drop(&mut self) {
unsafe {
match self.function.tag {
CApiExternTag::Function => mem::ManuallyDrop::drop(&mut self.function),
CApiExternTag::Global => mem::ManuallyDrop::drop(&mut self.global),
CApiExternTag::Table => mem::ManuallyDrop::drop(&mut self.table),
CApiExternTag::Memory => mem::ManuallyDrop::drop(&mut self.memory),
}
}
}
}
impl wasm_extern_t {
pub(crate) fn get_tag(&self) -> CApiExternTag {
unsafe { self.inner.function.tag }
}
pub(crate) fn ty(&self) -> ExternType {
match self.get_tag() {
CApiExternTag::Function => {
ExternType::Function(unsafe { self.inner.function.inner.ty().clone() })
}
CApiExternTag::Memory => {
ExternType::Memory(unsafe { self.inner.memory.inner.ty().clone() })
}
CApiExternTag::Global => {
ExternType::Global(unsafe { self.inner.global.inner.ty().clone() })
}
CApiExternTag::Table => {
ExternType::Table(unsafe { self.inner.table.inner.ty().clone() })
}
}
}
}
impl Clone for wasm_extern_t {
fn clone(&self) -> Self {
match self.get_tag() {
CApiExternTag::Function => Self {
inner: wasm_extern_inner {
function: unsafe { self.inner.function.clone() },
},
},
CApiExternTag::Memory => Self {
inner: wasm_extern_inner {
memory: unsafe { self.inner.memory.clone() },
},
},
CApiExternTag::Global => Self {
inner: wasm_extern_inner {
global: unsafe { self.inner.global.clone() },
},
},
CApiExternTag::Table => Self {
inner: wasm_extern_inner {
table: unsafe { self.inner.table.clone() },
},
},
}
}
}
impl From<Extern> for wasm_extern_t {
fn from(other: Extern) -> Self {
match other {
Extern::Function(function) => Self {
inner: wasm_extern_inner {
function: mem::ManuallyDrop::new(wasm_func_t::new(function)),
},
},
Extern::Memory(memory) => Self {
inner: wasm_extern_inner {
memory: mem::ManuallyDrop::new(wasm_memory_t::new(memory)),
},
},
Extern::Table(table) => Self {
inner: wasm_extern_inner {
table: mem::ManuallyDrop::new(wasm_table_t::new(table)),
},
},
Extern::Global(global) => Self {
inner: wasm_extern_inner {
global: mem::ManuallyDrop::new(wasm_global_t::new(global)),
},
},
}
}
}
impl From<wasm_extern_t> for Extern {
fn from(other: wasm_extern_t) -> Self {
match other.get_tag() {
CApiExternTag::Function => unsafe { (&*other.inner.function.inner).clone().into() },
CApiExternTag::Memory => unsafe { (&*other.inner.memory.inner).clone().into() },
CApiExternTag::Table => unsafe { (&*other.inner.table.inner).clone().into() },
CApiExternTag::Global => unsafe { (&*other.inner.global.inner).clone().into() },
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub(crate) enum CApiExternTag {
Function,
Global,
Table,
Memory,
} }
wasm_declare_boxed_vec!(extern); wasm_declare_boxed_vec!(extern);
@@ -31,106 +182,68 @@ pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box<wasm_
pub unsafe extern "C" fn wasm_extern_delete(_extern: Option<Box<wasm_extern_t>>) {} pub unsafe extern "C" fn wasm_extern_delete(_extern: Option<Box<wasm_extern_t>>) {}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_as_extern( pub extern "C" fn wasm_func_as_extern(func: Option<&wasm_func_t>) -> Option<&wasm_extern_t> {
func: Option<&wasm_func_t>, unsafe { mem::transmute::<Option<&wasm_func_t>, Option<&wasm_extern_t>>(func) }
) -> Option<Box<wasm_extern_t>> {
let func = func?;
Some(Box::new(wasm_extern_t {
instance: func.instance.clone(),
inner: Extern::Function(func.inner.clone()),
}))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_as_extern( pub extern "C" fn wasm_global_as_extern(global: Option<&wasm_global_t>) -> Option<&wasm_extern_t> {
global: Option<&wasm_global_t>, unsafe { mem::transmute::<Option<&wasm_global_t>, Option<&wasm_extern_t>>(global) }
) -> Option<Box<wasm_extern_t>> {
let global = global?;
Some(Box::new(wasm_extern_t {
// TODO: update this if global does hold onto an `instance`
instance: None,
inner: Extern::Global(global.inner.clone()),
}))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_as_extern( pub extern "C" fn wasm_memory_as_extern(memory: Option<&wasm_memory_t>) -> Option<&wasm_extern_t> {
memory: Option<&wasm_memory_t>, unsafe { mem::transmute::<Option<&wasm_memory_t>, Option<&wasm_extern_t>>(memory) }
) -> Option<Box<wasm_extern_t>> {
let memory = memory?;
Some(Box::new(wasm_extern_t {
// TODO: update this if global does hold onto an `instance`
instance: None,
inner: Extern::Memory(memory.inner.clone()),
}))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_table_as_extern( pub extern "C" fn wasm_table_as_extern(table: Option<&wasm_table_t>) -> Option<&wasm_extern_t> {
table: Option<&wasm_table_t>, unsafe { mem::transmute::<Option<&wasm_table_t>, Option<&wasm_extern_t>>(table) }
) -> Option<Box<wasm_extern_t>> {
let table = table?;
Some(Box::new(wasm_extern_t {
// TODO: update this if global does hold onto an `instance`
instance: None,
inner: Extern::Table(table.inner.clone()),
}))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_func( pub extern "C" fn wasm_extern_as_func(r#extern: Option<&wasm_extern_t>) -> Option<&wasm_func_t> {
r#extern: Option<&wasm_extern_t>,
) -> Option<Box<wasm_func_t>> {
let r#extern = r#extern?; let r#extern = r#extern?;
if let Extern::Function(f) = &r#extern.inner { if r#extern.get_tag() == CApiExternTag::Function {
Some(Box::new(wasm_func_t { Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_func_t>(r#extern) })
inner: f.clone(),
instance: r#extern.instance.clone(),
}))
} else { } else {
None None
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_global( pub extern "C" fn wasm_extern_as_global(
r#extern: Option<&wasm_extern_t>, r#extern: Option<&wasm_extern_t>,
) -> Option<Box<wasm_global_t>> { ) -> Option<&wasm_global_t> {
let r#extern = r#extern?; let r#extern = r#extern?;
if let Extern::Global(g) = &r#extern.inner { if r#extern.get_tag() == CApiExternTag::Global {
Some(Box::new(wasm_global_t { inner: g.clone() })) Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_global_t>(r#extern) })
} else { } else {
None None
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_memory( pub extern "C" fn wasm_extern_as_memory(
r#extern: Option<&wasm_extern_t>, r#extern: Option<&wasm_extern_t>,
) -> Option<Box<wasm_memory_t>> { ) -> Option<&wasm_memory_t> {
let r#extern = r#extern?; let r#extern = r#extern?;
if let Extern::Memory(m) = &r#extern.inner { if r#extern.get_tag() == CApiExternTag::Memory {
Some(Box::new(wasm_memory_t { inner: m.clone() })) Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_memory_t>(r#extern) })
} else { } else {
None None
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_table( pub extern "C" fn wasm_extern_as_table(r#extern: Option<&wasm_extern_t>) -> Option<&wasm_table_t> {
r#extern: Option<&wasm_extern_t>,
) -> Option<Box<wasm_table_t>> {
let r#extern = r#extern?; let r#extern = r#extern?;
if let Extern::Table(t) = &r#extern.inner { if r#extern.get_tag() == CApiExternTag::Table {
Some(Box::new(wasm_table_t { inner: t.clone() })) Some(unsafe { mem::transmute::<&wasm_extern_t, &wasm_table_t>(r#extern) })
} else { } else {
None None
} }

View File

@@ -1,11 +1,23 @@
use super::super::store::wasm_store_t; use super::super::store::wasm_store_t;
use super::super::types::{wasm_ref_t, wasm_table_size_t, wasm_tabletype_t}; use super::super::types::{wasm_ref_t, wasm_table_size_t, wasm_tabletype_t};
use super::CApiExternTag;
use wasmer::Table; use wasmer::Table;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Clone)]
pub struct wasm_table_t { pub struct wasm_table_t {
// maybe needs to hold onto instance pub(crate) tag: CApiExternTag,
pub(crate) inner: Table, pub(crate) inner: Box<Table>,
}
impl wasm_table_t {
pub(crate) fn new(table: Table) -> Self {
Self {
tag: CApiExternTag::Table,
inner: Box::new(table),
}
}
} }
#[no_mangle] #[no_mangle]
@@ -32,9 +44,7 @@ pub unsafe extern "C" fn wasm_table_delete(_table: Option<Box<wasm_table_t>>) {}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_table_copy(table: &wasm_table_t) -> Box<wasm_table_t> { pub unsafe extern "C" fn wasm_table_copy(table: &wasm_table_t) -> Box<wasm_table_t> {
// do shallow copy // do shallow copy
Box::new(wasm_table_t { Box::new(wasm_table_t::new((&*table.inner).clone()))
inner: table.inner.clone(),
})
} }
#[no_mangle] #[no_mangle]

View File

@@ -53,9 +53,8 @@ pub unsafe extern "C" fn wasm_instance_new(
.into_slice() .into_slice()
.map(|imports| imports.iter()) .map(|imports| imports.iter())
.unwrap_or_else(|| [].iter()) .unwrap_or_else(|| [].iter())
.map(|imp| &imp.inner) .map(|imp| Extern::from((&**imp).clone()))
.take(module_import_count) .take(module_import_count)
.cloned()
.collect(); .collect();
let instance = match Instance::new(wasm_module, &resolver) { let instance = match Instance::new(wasm_module, &resolver) {
@@ -192,10 +191,7 @@ pub unsafe extern "C" fn wasm_instance_exports(
None None
}; };
Box::into_raw(Box::new(wasm_extern_t { Box::into_raw(Box::new(r#extern.clone().into()))
instance: Some(Arc::clone(instance)),
inner: r#extern.clone(),
}))
}) })
.collect::<Vec<*mut wasm_extern_t>>(); .collect::<Vec<*mut wasm_extern_t>>();
extern_vec.shrink_to_fit(); extern_vec.shrink_to_fit();

View File

@@ -1,10 +1,10 @@
use super::{wasm_externtype_t, wasm_name_t}; use super::{owned_wasm_name_t, wasm_externtype_t, wasm_name_t};
use wasmer::ExportType; use wasmer::ExportType;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[derive(Clone)]
pub struct wasm_exporttype_t { pub struct wasm_exporttype_t {
name: Box<wasm_name_t>, name: owned_wasm_name_t,
extern_type: Box<wasm_externtype_t>, extern_type: Box<wasm_externtype_t>,
} }
@@ -12,11 +12,12 @@ wasm_declare_boxed_vec!(exporttype);
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_exporttype_new( pub extern "C" fn wasm_exporttype_new(
name: Option<Box<wasm_name_t>>, name: Option<&wasm_name_t>,
extern_type: Option<Box<wasm_externtype_t>>, extern_type: Option<Box<wasm_externtype_t>>,
) -> Option<Box<wasm_exporttype_t>> { ) -> Option<Box<wasm_exporttype_t>> {
let name = unsafe { owned_wasm_name_t::new(name?) };
Some(Box::new(wasm_exporttype_t { Some(Box::new(wasm_exporttype_t {
name: name?, name,
extern_type: extern_type?, extern_type: extern_type?,
})) }))
} }
@@ -42,7 +43,7 @@ impl From<ExportType> for wasm_exporttype_t {
impl From<&ExportType> for wasm_exporttype_t { impl From<&ExportType> for wasm_exporttype_t {
fn from(other: &ExportType) -> Self { fn from(other: &ExportType) -> Self {
let name: Box<wasm_name_t> = Box::new(other.name().to_string().into()); let name: owned_wasm_name_t = other.name().to_string().into();
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into()); let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into());
wasm_exporttype_t { name, extern_type } wasm_exporttype_t { name, extern_type }

View File

@@ -85,12 +85,12 @@ impl From<&ExternType> for wasm_externtype_t {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_type(r#extern: &wasm_extern_t) -> Box<wasm_externtype_t> { pub unsafe extern "C" fn wasm_extern_type(r#extern: &wasm_extern_t) -> Box<wasm_externtype_t> {
Box::new(wasm_externtype_t::new(r#extern.inner.ty())) Box::new(wasm_externtype_t::new(r#extern.ty()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_kind(r#extern: &wasm_extern_t) -> wasm_externkind_t { pub unsafe extern "C" fn wasm_extern_kind(r#extern: &wasm_extern_t) -> wasm_externkind_t {
wasm_externkind_enum::from(r#extern.inner.ty()) as wasm_externkind_t wasm_externkind_enum::from(r#extern.ty()) as wasm_externkind_t
} }
#[no_mangle] #[no_mangle]

View File

@@ -1,11 +1,12 @@
use super::{wasm_externtype_t, wasm_name_t}; use super::{owned_wasm_name_t, wasm_externtype_t, wasm_name_t};
use wasmer::ImportType; use wasmer::ImportType;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[derive(Clone)]
#[repr(C)]
pub struct wasm_importtype_t { pub struct wasm_importtype_t {
module: Box<wasm_name_t>, module: owned_wasm_name_t,
name: Box<wasm_name_t>, name: owned_wasm_name_t,
extern_type: Box<wasm_externtype_t>, extern_type: Box<wasm_externtype_t>,
} }
@@ -13,13 +14,19 @@ wasm_declare_boxed_vec!(importtype);
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_importtype_new( pub extern "C" fn wasm_importtype_new(
module: Option<Box<wasm_name_t>>, module: Option<&wasm_name_t>,
name: Option<Box<wasm_name_t>>, name: Option<&wasm_name_t>,
extern_type: Option<Box<wasm_externtype_t>>, extern_type: Option<Box<wasm_externtype_t>>,
) -> Option<Box<wasm_importtype_t>> { ) -> Option<Box<wasm_importtype_t>> {
let (module, name) = unsafe {
(
owned_wasm_name_t::new(module?),
owned_wasm_name_t::new(name?),
)
};
Some(Box::new(wasm_importtype_t { Some(Box::new(wasm_importtype_t {
name: name?, name,
module: module?, module,
extern_type: extern_type?, extern_type: extern_type?,
})) }))
} }
@@ -50,8 +57,8 @@ impl From<ImportType> for wasm_importtype_t {
impl From<&ImportType> for wasm_importtype_t { impl From<&ImportType> for wasm_importtype_t {
fn from(other: &ImportType) -> Self { fn from(other: &ImportType) -> Self {
let module: Box<wasm_name_t> = Box::new(other.module().to_string().into()); let module: owned_wasm_name_t = other.module().to_string().into();
let name: Box<wasm_name_t> = Box::new(other.name().to_string().into()); let name: owned_wasm_name_t = other.name().to_string().into();
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into()); let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into());
wasm_importtype_t { wasm_importtype_t {

View File

@@ -28,16 +28,63 @@ wasm_declare_vec!(byte);
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_name_t = wasm_byte_vec_t; pub type wasm_name_t = wasm_byte_vec_t;
impl From<String> for wasm_name_t { impl AsRef<wasm_name_t> for wasm_name_t {
fn as_ref(&self) -> &wasm_name_t {
&self
}
}
/// An owned version of `wasm_name_t`.
///
/// Assumes that data is either valid host-owned or null.
// NOTE: `wasm_name_t` already does a deep copy, so we just derive `Clone` here.
#[derive(Debug, Clone)]
#[repr(transparent)]
#[allow(non_camel_case_types)]
pub struct owned_wasm_name_t(wasm_name_t);
impl owned_wasm_name_t {
/// Take ownership of some `wasm_name_t`
///
/// # Safety
/// You must ensure that the data pointed to by `wasm_name_t` is valid and
/// that it is not owned by anyone else.
pub unsafe fn new(name: &wasm_name_t) -> Self {
Self(wasm_name_t {
size: name.size,
data: name.data,
})
}
}
impl Drop for owned_wasm_name_t {
fn drop(&mut self) {
if !self.0.data.is_null() {
let _v = unsafe { Vec::from_raw_parts(self.0.data, self.0.size, self.0.size) };
self.0.data = std::ptr::null_mut();
self.0.size = 0;
}
// why can't we call this function?
//unsafe { crate::wasm_c_api::macros::wasm_byte_vec_delete(Some(self.0)) }
}
}
impl AsRef<wasm_name_t> for owned_wasm_name_t {
fn as_ref(&self) -> &wasm_name_t {
&self.0
}
}
impl From<String> for owned_wasm_name_t {
fn from(string: String) -> Self { fn from(string: String) -> Self {
let mut boxed_str: Box<str> = string.into_boxed_str(); let mut boxed_str: Box<str> = string.into_boxed_str();
let data = boxed_str.as_mut_ptr(); let data = boxed_str.as_mut_ptr();
let size = boxed_str.bytes().len(); let size = boxed_str.bytes().len();
let wasm_name = Self { data, size }; let wasm_name = wasm_name_t { data, size };
Box::leak(boxed_str); Box::leak(boxed_str);
wasm_name Self(wasm_name)
} }
} }

View File

@@ -2,7 +2,10 @@
//! API. //! API.
use super::super::{ use super::super::{
externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t, externals::wasm_extern_t,
module::wasm_module_t,
store::wasm_store_t,
types::{owned_wasm_name_t, wasm_name_t},
wasi::wasi_env_t, wasi::wasi_env_t,
}; };
use crate::error::CApiError; use crate::error::CApiError;
@@ -19,8 +22,8 @@ use wasmer_wasi::{generate_import_object_from_env, get_wasi_version};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[derive(Clone)]
pub struct wasmer_named_extern_t { pub struct wasmer_named_extern_t {
module: Box<wasm_name_t>, module: owned_wasm_name_t,
name: Box<wasm_name_t>, name: owned_wasm_name_t,
r#extern: Box<wasm_extern_t>, r#extern: Box<wasm_extern_t>,
} }
@@ -179,17 +182,14 @@ fn wasi_get_unordered_imports_inner(
*imports = import_object *imports = import_object
.into_iter() .into_iter()
.map(|((module, name), export)| { .map(|((module, name), export)| {
let module = Box::new(module.into()); let module = module.into();
let name = Box::new(name.into()); let name = name.into();
let extern_inner = Extern::from_vm_export(store, export); let extern_inner = Extern::from_vm_export(store, export);
Box::new(wasmer_named_extern_t { Box::new(wasmer_named_extern_t {
module, module,
name, name,
r#extern: Box::new(wasm_extern_t { r#extern: Box::new(extern_inner.into()),
instance: None,
inner: extern_inner,
}),
}) })
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()

View File

@@ -6,7 +6,7 @@ mod capture_files;
pub use super::unstable::wasi::wasi_get_unordered_imports; pub use super::unstable::wasi::wasi_get_unordered_imports;
use super::{ use super::{
externals::{wasm_extern_t, wasm_extern_vec_t, wasm_func_t, wasm_memory_t}, externals::{wasm_extern_vec_t, wasm_func_t, wasm_memory_t},
instance::wasm_instance_t, instance::wasm_instance_t,
module::wasm_module_t, module::wasm_module_t,
store::wasm_store_t, store::wasm_store_t,
@@ -390,10 +390,7 @@ fn wasi_get_imports_inner(
})); }));
let inner = Extern::from_vm_export(store, export); let inner = Extern::from_vm_export(store, export);
Some(Box::new(wasm_extern_t { Some(Box::new(inner.into()))
instance: None,
inner,
}))
}) })
.collect::<Option<Vec<_>>>()? .collect::<Option<Vec<_>>>()?
.into(); .into();
@@ -407,10 +404,7 @@ pub unsafe extern "C" fn wasi_get_start_function(
) -> Option<Box<wasm_func_t>> { ) -> Option<Box<wasm_func_t>> {
let start = c_try!(instance.inner.exports.get_function("_start")); let start = c_try!(instance.inner.exports.get_function("_start"));
Some(Box::new(wasm_func_t { Some(Box::new(wasm_func_t::new(start.clone())))
inner: start.clone(),
instance: Some(instance.inner.clone()),
}))
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -90,8 +90,6 @@ int main(int argc, const char *argv[]) {
return 1; return 1;
} }
wasm_func_delete(host_func);
// Extract export. // Extract export.
printf("Extracting export...\n"); printf("Extracting export...\n");
own wasm_extern_vec_t exports; own wasm_extern_vec_t exports;

View File

@@ -8,27 +8,27 @@ use std::path::PathBuf;
/// The options for the `wasmer config` subcommand /// The options for the `wasmer config` subcommand
pub struct Config { pub struct Config {
/// Print the installation prefix. /// Print the installation prefix.
#[clap(long, conflicts_with = "pkg_config")] #[clap(long, conflicts_with = "pkg-config")]
prefix: bool, prefix: bool,
/// Directory containing Wasmer executables. /// Directory containing Wasmer executables.
#[clap(long, conflicts_with = "pkg_config")] #[clap(long, conflicts_with = "pkg-config")]
bindir: bool, bindir: bool,
/// Directory containing Wasmer headers. /// Directory containing Wasmer headers.
#[clap(long, conflicts_with = "pkg_config")] #[clap(long, conflicts_with = "pkg-config")]
includedir: bool, includedir: bool,
/// Directory containing Wasmer libraries. /// Directory containing Wasmer libraries.
#[clap(long, conflicts_with = "pkg_config")] #[clap(long, conflicts_with = "pkg-config")]
libdir: bool, libdir: bool,
/// Libraries needed to link against Wasmer components. /// Libraries needed to link against Wasmer components.
#[clap(long, conflicts_with = "pkg_config")] #[clap(long, conflicts_with = "pkg-config")]
libs: bool, libs: bool,
/// C compiler flags for files that include Wasmer headers. /// C compiler flags for files that include Wasmer headers.
#[clap(long, conflicts_with = "pkg_config")] #[clap(long, conflicts_with = "pkg-config")]
cflags: bool, cflags: bool,
/// It outputs the necessary details for compiling /// It outputs the necessary details for compiling

View File

@@ -20,11 +20,11 @@ pub struct StoreOptions {
compiler: CompilerOptions, compiler: CompilerOptions,
/// Use JIT Engine. /// Use JIT Engine.
#[clap(long, conflicts_with_all = &["native", "object_file"])] #[clap(long, conflicts_with_all = &["native", "object-file"])]
jit: bool, jit: bool,
/// Use Native Engine. /// Use Native Engine.
#[clap(long, conflicts_with_all = &["jit", "object_file"])] #[clap(long, conflicts_with_all = &["jit", "object-file"])]
native: bool, native: bool,
/// Use ObjectFile Engine. /// Use ObjectFile Engine.
@@ -212,18 +212,19 @@ impl CompilerOptions {
// Converts a kind into a filename, that we will use to dump // Converts a kind into a filename, that we will use to dump
// the contents of the IR object file to. // the contents of the IR object file to.
fn types_to_signature(types: &[Type]) -> String { fn types_to_signature(types: &[Type]) -> String {
types.iter().map(|ty| { types
match ty { .iter()
.map(|ty| match ty {
Type::I32 => "i".to_string(), Type::I32 => "i".to_string(),
Type::I64 => "I".to_string(), Type::I64 => "I".to_string(),
Type::F32 => "f".to_string(), Type::F32 => "f".to_string(),
Type::F64 => "F".to_string(), Type::F64 => "F".to_string(),
Type::V128 => "v".to_string(), Type::V128 => "v".to_string(),
_ => { Type::ExternRef => "e".to_string(),
unimplemented!("Function type not yet supported for generated signatures in debugging"); Type::FuncRef => "r".to_string(),
} })
} .collect::<Vec<_>>()
}).collect::<Vec<_>>().join("") .join("")
} }
// Converts a kind into a filename, that we will use to dump // Converts a kind into a filename, that we will use to dump
// the contents of the IR object file to. // the contents of the IR object file to.

View File

@@ -152,6 +152,9 @@ impl Cranelift {
flags flags
.set("enable_verifier", enable_verifier) .set("enable_verifier", enable_verifier)
.expect("should be valid flag"); .expect("should be valid flag");
flags
.set("enable_safepoints", "true")
.expect("should be valid flag");
let opt_level = if self.enable_simd { let opt_level = if self.enable_simd {
"none" "none"

View File

@@ -11,13 +11,16 @@ use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Signature}; use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Signature};
use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_frontend::FunctionBuilder; use cranelift_frontend::{FunctionBuilder, Variable};
use std::convert::TryFrom; use std::convert::TryFrom;
use wasmer_compiler::wasmparser::Type; use wasmer_compiler::wasmparser::Type;
use wasmer_compiler::{WasmError, WasmResult}; use wasmer_compiler::{WasmError, WasmResult};
use wasmer_types::entity::EntityRef; use wasmer_types::entity::EntityRef;
use wasmer_types::entity::PrimaryMap; use wasmer_types::entity::PrimaryMap;
use wasmer_types::{FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex}; use wasmer_types::{
FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex,
TableIndex, Type as WasmerType,
};
use wasmer_vm::VMBuiltinFunctionIndex; use wasmer_vm::VMBuiltinFunctionIndex;
use wasmer_vm::VMOffsets; use wasmer_vm::VMOffsets;
use wasmer_vm::{MemoryStyle, ModuleInfo, TableStyle}; use wasmer_vm::{MemoryStyle, ModuleInfo, TableStyle};
@@ -45,6 +48,9 @@ pub struct FuncEnvironment<'module_environment> {
/// The module-level environment which this function-level environment belongs to. /// The module-level environment which this function-level environment belongs to.
module: &'module_environment ModuleInfo, module: &'module_environment ModuleInfo,
/// A stack tracking the type of local variables.
type_stack: Vec<WasmerType>,
/// The module function signatures /// The module function signatures
signatures: &'module_environment PrimaryMap<SignatureIndex, ir::Signature>, signatures: &'module_environment PrimaryMap<SignatureIndex, ir::Signature>,
@@ -55,10 +61,18 @@ pub struct FuncEnvironment<'module_environment> {
/// for locally-defined 32-bit memories. /// for locally-defined 32-bit memories.
memory32_size_sig: Option<ir::SigRef>, memory32_size_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.size`
/// for locally-defined tables.
table_size_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `memory.grow` /// The external function signature for implementing wasm's `memory.grow`
/// for locally-defined memories. /// for locally-defined memories.
memory_grow_sig: Option<ir::SigRef>, memory_grow_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.grow`
/// for locally-defined tables.
table_grow_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.copy` /// The external function signature for implementing wasm's `table.copy`
/// (it's the same for both local and imported tables). /// (it's the same for both local and imported tables).
table_copy_sig: Option<ir::SigRef>, table_copy_sig: Option<ir::SigRef>,
@@ -83,6 +97,23 @@ pub struct FuncEnvironment<'module_environment> {
/// The external function signature for implementing wasm's `data.drop`. /// The external function signature for implementing wasm's `data.drop`.
data_drop_sig: Option<ir::SigRef>, data_drop_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.get`.
table_get_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.set`.
table_set_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `func.ref`.
func_ref_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.fill`.
table_fill_sig: Option<ir::SigRef>,
/// The external function signature for implementing reference increment for `extern.ref`.
externref_inc_sig: Option<ir::SigRef>,
/// The external function signature for implementing reference decrement for `extern.ref`.
externref_dec_sig: Option<ir::SigRef>,
/// Offsets to struct fields accessed by JIT code. /// Offsets to struct fields accessed by JIT code.
offsets: VMOffsets, offsets: VMOffsets,
@@ -105,16 +136,25 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
target_config, target_config,
module, module,
signatures, signatures,
type_stack: vec![],
vmctx: None, vmctx: None,
memory32_size_sig: None, memory32_size_sig: None,
table_size_sig: None,
memory_grow_sig: None, memory_grow_sig: None,
table_grow_sig: None,
table_copy_sig: None, table_copy_sig: None,
table_init_sig: None, table_init_sig: None,
elem_drop_sig: None, elem_drop_sig: None,
memory_copy_sig: None, memory_copy_sig: None,
memory_fill_sig: None, memory_fill_sig: None,
memory_init_sig: None, memory_init_sig: None,
table_get_sig: None,
table_set_sig: None,
data_drop_sig: None, data_drop_sig: None,
func_ref_sig: None,
table_fill_sig: None,
externref_inc_sig: None,
externref_dec_sig: None,
offsets: VMOffsets::new(target_config.pointer_bytes(), module), offsets: VMOffsets::new(target_config.pointer_bytes(), module),
memory_styles, memory_styles,
table_styles, table_styles,
@@ -133,6 +173,224 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
}) })
} }
fn get_table_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.table_fill_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// table index
AbiParam::new(I32),
// dst
AbiParam::new(I32),
// value
AbiParam::new(R64),
// len
AbiParam::new(I32),
],
returns: vec![],
call_conv: self.target_config.default_call_conv,
})
});
self.table_fill_sig = Some(sig);
sig
}
fn get_table_fill_func(
&mut self,
func: &mut Function,
table_index: TableIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
(
self.get_table_fill_sig(func),
table_index.index(),
VMBuiltinFunctionIndex::get_table_fill_index(),
)
}
fn get_externref_inc_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.externref_inc_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![AbiParam::new(R64)],
returns: vec![],
call_conv: self.target_config.default_call_conv,
})
});
self.externref_inc_sig = Some(sig);
sig
}
fn get_externref_inc_func(
&mut self,
func: &mut Function,
) -> (ir::SigRef, VMBuiltinFunctionIndex) {
(
self.get_externref_inc_sig(func),
VMBuiltinFunctionIndex::get_externref_inc_index(),
)
}
fn get_externref_dec_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.externref_dec_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![AbiParam::new(R64)],
returns: vec![],
call_conv: self.target_config.default_call_conv,
})
});
self.externref_dec_sig = Some(sig);
sig
}
fn get_externref_dec_func(
&mut self,
func: &mut Function,
) -> (ir::SigRef, VMBuiltinFunctionIndex) {
(
self.get_externref_dec_sig(func),
VMBuiltinFunctionIndex::get_externref_dec_index(),
)
}
fn get_func_ref_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.func_ref_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
AbiParam::new(I32),
],
returns: vec![AbiParam::new(R64)],
call_conv: self.target_config.default_call_conv,
})
});
self.func_ref_sig = Some(sig);
sig
}
fn get_func_ref_func(
&mut self,
func: &mut Function,
function_index: FunctionIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
(
self.get_func_ref_sig(func),
function_index.index(),
VMBuiltinFunctionIndex::get_func_ref_index(),
)
}
fn get_table_get_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.table_get_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
AbiParam::new(I32),
AbiParam::new(I32),
],
returns: vec![AbiParam::new(R64)],
call_conv: self.target_config.default_call_conv,
})
});
self.table_get_sig = Some(sig);
sig
}
fn get_table_get_func(
&mut self,
func: &mut Function,
table_index: TableIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_table(table_index) {
(
self.get_table_get_sig(func),
table_index.index(),
VMBuiltinFunctionIndex::get_imported_table_get_index(),
)
} else {
(
self.get_table_get_sig(func),
self.module.local_table_index(table_index).unwrap().index(),
VMBuiltinFunctionIndex::get_table_get_index(),
)
}
}
fn get_table_set_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.table_set_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
AbiParam::new(I32),
AbiParam::new(I32),
AbiParam::new(R64),
],
returns: vec![],
call_conv: self.target_config.default_call_conv,
})
});
self.table_set_sig = Some(sig);
sig
}
fn get_table_set_func(
&mut self,
func: &mut Function,
table_index: TableIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_table(table_index) {
(
self.get_table_set_sig(func),
table_index.index(),
VMBuiltinFunctionIndex::get_imported_table_set_index(),
)
} else {
(
self.get_table_set_sig(func),
self.module.local_table_index(table_index).unwrap().index(),
VMBuiltinFunctionIndex::get_table_set_index(),
)
}
}
fn get_table_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.table_grow_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// TODO: figure out what the representation of a Wasm value is
AbiParam::new(R64),
AbiParam::new(I32),
AbiParam::new(I32),
],
returns: vec![AbiParam::new(I32)],
call_conv: self.target_config.default_call_conv,
})
});
self.table_grow_sig = Some(sig);
sig
}
/// Return the table.grow function signature to call for the given index, along with the
/// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
fn get_table_grow_func(
&mut self,
func: &mut Function,
index: TableIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_table(index) {
(
self.get_table_grow_sig(func),
index.index(),
VMBuiltinFunctionIndex::get_imported_table_grow_index(),
)
} else {
(
self.get_table_grow_sig(func),
self.module.local_table_index(index).unwrap().index(),
VMBuiltinFunctionIndex::get_table_grow_index(),
)
}
}
fn get_memory_grow_sig(&mut self, func: &mut Function) -> ir::SigRef { fn get_memory_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.memory_grow_sig.unwrap_or_else(|| { let sig = self.memory_grow_sig.unwrap_or_else(|| {
func.import_signature(Signature { func.import_signature(Signature {
@@ -171,6 +429,43 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
} }
} }
fn get_table_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.table_size_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
AbiParam::new(I32),
],
returns: vec![AbiParam::new(I32)],
call_conv: self.target_config.default_call_conv,
})
});
self.table_size_sig = Some(sig);
sig
}
/// Return the memory.size function signature to call for the given index, along with the
/// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
fn get_table_size_func(
&mut self,
func: &mut Function,
index: TableIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_table(index) {
(
self.get_table_size_sig(func),
index.index(),
VMBuiltinFunctionIndex::get_imported_table_size_index(),
)
} else {
(
self.get_table_size_sig(func),
self.module.local_table_index(index).unwrap().index(),
VMBuiltinFunctionIndex::get_table_size_index(),
)
}
}
fn get_memory32_size_sig(&mut self, func: &mut Function) -> ir::SigRef { fn get_memory32_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.memory32_size_sig.unwrap_or_else(|| { let sig = self.memory32_size_sig.unwrap_or_else(|| {
func.import_signature(Signature { func.import_signature(Signature {
@@ -338,7 +633,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
( (
sig, sig,
local_memory_index.index(), local_memory_index.index(),
VMBuiltinFunctionIndex::get_local_memory_copy_index(), VMBuiltinFunctionIndex::get_memory_copy_index(),
) )
} else { } else {
( (
@@ -524,9 +819,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
}); });
let element_size = match self.table_styles[index] { let element_size = match self.table_styles[index] {
TableStyle::CallerChecksSignature => { TableStyle::CallerChecksSignature => u64::from(self.offsets.size_of_vm_funcref()),
u64::from(self.offsets.size_of_vmcaller_checked_anyfunc())
}
}; };
Ok(func.create_table(ir::TableData { Ok(func.create_table(ir::TableData {
@@ -540,53 +833,107 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_grow( fn translate_table_grow(
&mut self, &mut self,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>, mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
_table_index: TableIndex, table_index: TableIndex,
_table: ir::Table, _table: ir::Table,
_delta: ir::Value, delta: ir::Value,
_init_value: ir::Value, init_value: ir::Value,
) -> WasmResult<ir::Value> { ) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported( let (func_sig, index_arg, func_idx) = self.get_table_grow_func(&mut pos.func, table_index);
"the `table.grow` instruction is not supported yet".into(), let table_index = pos.ins().iconst(I32, index_arg as i64);
)) let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let call_inst = pos.ins().call_indirect(
func_sig,
func_addr,
&[vmctx, init_value, delta, table_index],
);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
} }
fn translate_table_get( fn translate_table_get(
&mut self, &mut self,
_builder: &mut FunctionBuilder, builder: &mut FunctionBuilder,
_table_index: TableIndex, table_index: TableIndex,
_table: ir::Table, _table: ir::Table,
_index: ir::Value, index: ir::Value,
) -> WasmResult<ir::Value> { ) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported( let mut pos = builder.cursor();
"the `table.get` instruction is not supported yet".into(),
)) let (func_sig, table_index_arg, func_idx) =
self.get_table_get_func(&mut pos.func, table_index);
let table_index = pos.ins().iconst(I32, table_index_arg as i64);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let call_inst = pos
.ins()
.call_indirect(func_sig, func_addr, &[vmctx, table_index, index]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
} }
fn translate_table_set( fn translate_table_set(
&mut self, &mut self,
_builder: &mut FunctionBuilder, builder: &mut FunctionBuilder,
_table_index: TableIndex, table_index: TableIndex,
_table: ir::Table, _table: ir::Table,
_value: ir::Value, value: ir::Value,
_index: ir::Value, index: ir::Value,
) -> WasmResult<()> { ) -> WasmResult<()> {
Err(WasmError::Unsupported( let mut pos = builder.cursor();
"the `table.set` instruction is not supported yet".into(),
)) let (func_sig, table_index_arg, func_idx) =
self.get_table_set_func(&mut pos.func, table_index);
let table_index = pos.ins().iconst(I32, table_index_arg as i64);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
pos.ins()
.call_indirect(func_sig, func_addr, &[vmctx, table_index, index, value]);
Ok(())
} }
fn translate_table_fill( fn translate_table_fill(
&mut self, &mut self,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>, mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
_table_index: TableIndex, table_index: TableIndex,
_dst: ir::Value, dst: ir::Value,
_val: ir::Value, val: ir::Value,
_len: ir::Value, len: ir::Value,
) -> WasmResult<()> { ) -> WasmResult<()> {
Err(WasmError::Unsupported( let (func_sig, table_index_arg, func_idx) =
"the `table.fill` instruction is not supported yet".into(), self.get_table_fill_func(&mut pos.func, table_index);
)) let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
pos.ins().call_indirect(
func_sig,
func_addr,
&[vmctx, table_index_arg, dst, val, len],
);
Ok(())
}
fn translate_externref_inc(
&mut self,
mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
externref: ir::Value,
) -> WasmResult<()> {
let (func_sig, func_idx) = self.get_externref_inc_func(&mut pos.func);
let (_vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
pos.ins().call_indirect(func_sig, func_addr, &[externref]);
Ok(())
}
fn translate_externref_dec(
&mut self,
mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
externref: ir::Value,
) -> WasmResult<()> {
let (func_sig, func_idx) = self.get_externref_dec_func(&mut pos.func);
let (_vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
pos.ins().call_indirect(func_sig, func_addr, &[externref]);
Ok(())
} }
fn translate_ref_null( fn translate_ref_null(
@@ -595,11 +942,11 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
ty: Type, ty: Type,
) -> WasmResult<ir::Value> { ) -> WasmResult<ir::Value> {
Ok(match ty { Ok(match ty {
Type::FuncRef => pos.ins().iconst(self.pointer_type(), 0), Type::FuncRef => pos.ins().null(self.reference_type()),
// Type::ExternRef => pos.ins().null(self.reference_type(ty)), Type::ExternRef => pos.ins().null(self.reference_type()),
_ => { _ => {
return Err(WasmError::Unsupported( return Err(WasmError::Unsupported(
"`ref.null T` that is not a `funcref`".into(), "`ref.null T` that is not a `funcref` or an `externref`".into(),
)); ));
} }
}) })
@@ -626,12 +973,27 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_ref_func( fn translate_ref_func(
&mut self, &mut self,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>, mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
_func_index: FunctionIndex, func_index: FunctionIndex,
) -> WasmResult<ir::Value> { ) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported( // TODO: optimize this by storing a pointer to local func_index funcref metadata
"the `ref.func` instruction is not supported yet".into(), // so that local funcref is just (*global + offset) instead of a function call
)) //
// Actually we can do the above for both local and imported functions because
// all of those are known statically.
//
// prototyping with a function call though
let (func_sig, func_index_arg, func_idx) =
self.get_func_ref_func(&mut pos.func, func_index);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let func_index_arg = pos.ins().iconst(I32, func_index_arg as i64);
let call_inst = pos
.ins()
.call_indirect(func_sig, func_addr, &[vmctx, func_index_arg]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
} }
fn translate_custom_global_get( fn translate_custom_global_get(
@@ -797,6 +1159,17 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
// Dereference table_entry_addr to get the function address. // Dereference table_entry_addr to get the function address.
let mem_flags = ir::MemFlags::trusted(); let mem_flags = ir::MemFlags::trusted();
let table_entry_addr = pos.ins().load(
pointer_type,
mem_flags,
table_entry_addr,
i32::from(self.offsets.vm_funcref_anyfunc_ptr()),
);
// check if the funcref is null
pos.ins()
.trapz(table_entry_addr, ir::TrapCode::IndirectCallToNull);
let func_addr = pos.ins().load( let func_addr = pos.ins().load(
pointer_type, pointer_type,
mem_flags, mem_flags,
@@ -804,9 +1177,6 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()), i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()),
); );
// Check whether `func_addr` is null.
pos.ins().trapz(func_addr, ir::TrapCode::IndirectCallToNull);
// If necessary, check the signature. // If necessary, check the signature.
match self.table_styles[table_index] { match self.table_styles[table_index] {
TableStyle::CallerChecksSignature => { TableStyle::CallerChecksSignature => {
@@ -1019,13 +1389,17 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_size( fn translate_table_size(
&mut self, &mut self,
mut _pos: FuncCursor, mut pos: FuncCursor,
_table_index: TableIndex, table_index: TableIndex,
_table: ir::Table, _table: ir::Table,
) -> WasmResult<ir::Value> { ) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported( let (func_sig, index_arg, func_idx) = self.get_table_size_func(&mut pos.func, table_index);
"bulk memory: `table.size`".to_string(), let table_index = pos.ins().iconst(I32, index_arg as i64);
)) let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let call_inst = pos
.ins()
.call_indirect(func_sig, func_addr, &[vmctx, table_index]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
} }
fn translate_table_copy( fn translate_table_copy(
@@ -1129,4 +1503,50 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
"wasm atomics (fn translate_atomic_notify)".to_string(), "wasm atomics (fn translate_atomic_notify)".to_string(),
)) ))
} }
fn get_global_type(&self, global_index: GlobalIndex) -> Option<WasmerType> {
Some(self.module.globals.get(global_index)?.ty)
}
fn push_local_decl_on_stack(&mut self, ty: WasmerType) {
self.type_stack.push(ty);
}
fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex) {
let func_index = self.module.func_index(function_index);
let sig_idx = self.module.functions[func_index];
let signature = &self.module.signatures[sig_idx];
for param in signature.params() {
self.type_stack.push(*param);
}
}
fn get_local_type(&self, local_index: u32) -> Option<WasmerType> {
self.type_stack.get(local_index as usize).cloned()
}
fn get_local_types(&self) -> &[WasmerType] {
&self.type_stack
}
fn get_function_type(&self, function_index: FunctionIndex) -> Option<&FunctionType> {
let sig_idx = self.module.functions.get(function_index)?;
Some(&self.module.signatures[*sig_idx])
}
fn get_function_sig(&self, sig_index: SignatureIndex) -> Option<&FunctionType> {
self.module.signatures.get(sig_index)
}
fn translate_drop_locals(&mut self, builder: &mut FunctionBuilder) -> WasmResult<()> {
// TODO: this allocation can be removed without too much effort but it will require
// maneuvering around the borrow checker
for (local_index, local_type) in self.type_stack.to_vec().iter().enumerate() {
if *local_type == WasmerType::ExternRef {
let val = builder.use_var(Variable::with_u32(local_index as _));
self.translate_externref_dec(builder.cursor(), val)?;
}
}
Ok(())
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,10 @@ use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_frontend::FunctionBuilder; use cranelift_frontend::FunctionBuilder;
use wasmer_compiler::wasmparser::{Operator, Type}; use wasmer_compiler::wasmparser::{Operator, Type};
use wasmer_compiler::WasmResult; use wasmer_compiler::WasmResult;
use wasmer_types::{FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex}; use wasmer_types::{
FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex,
TableIndex, Type as WasmerType,
};
/// The value of a WebAssembly global variable. /// The value of a WebAssembly global variable.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@@ -333,6 +336,20 @@ pub trait FuncEnvironment: TargetEnvironment {
len: ir::Value, len: ir::Value,
) -> WasmResult<()>; ) -> WasmResult<()>;
/// Translates an externref ref count increment.
fn translate_externref_inc(
&mut self,
pos: cranelift_codegen::cursor::FuncCursor<'_>,
externref: ir::Value,
) -> WasmResult<()>;
/// Translates an externref ref count decrement.
fn translate_externref_dec(
&mut self,
pos: cranelift_codegen::cursor::FuncCursor<'_>,
externref: ir::Value,
) -> WasmResult<()>;
/// Translate a `table.init` WebAssembly instruction. /// Translate a `table.init` WebAssembly instruction.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn translate_table_init( fn translate_table_init(
@@ -378,7 +395,7 @@ pub trait FuncEnvironment: TargetEnvironment {
value: ir::Value, value: ir::Value,
) -> WasmResult<ir::Value> { ) -> WasmResult<ir::Value> {
let is_null = pos.ins().is_null(value); let is_null = pos.ins().is_null(value);
Ok(pos.ins().bint(ir::types::I32, is_null)) Ok(pos.ins().bint(ir::types::I64, is_null))
} }
/// Translate a `ref.func` WebAssembly instruction. /// Translate a `ref.func` WebAssembly instruction.
@@ -467,4 +484,28 @@ pub trait FuncEnvironment: TargetEnvironment {
) -> WasmResult<()> { ) -> WasmResult<()> {
Ok(()) Ok(())
} }
/// Get the type of the global at the given index.
fn get_global_type(&self, global_index: GlobalIndex) -> Option<WasmerType>;
/// Push a local declaration on to the stack to track the type of locals.
fn push_local_decl_on_stack(&mut self, ty: WasmerType);
/// Push locals for a the params of a function on to the stack.
fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex);
/// Get the type of the local at the given index.
fn get_local_type(&self, local_index: u32) -> Option<WasmerType>;
/// Get the types of all the current locals.
fn get_local_types(&self) -> &[WasmerType];
/// Get the type of the local at the given index.
fn get_function_type(&self, function_index: FunctionIndex) -> Option<&FunctionType>;
/// Get the type of a function with the given signature index.
fn get_function_sig(&self, sig_index: SignatureIndex) -> Option<&FunctionType>;
/// Drops all locals that need to be dropped. Useful for returning from functions.
fn translate_drop_locals(&mut self, builder: &mut FunctionBuilder) -> WasmResult<()>;
} }

View File

@@ -213,6 +213,13 @@ impl ControlStackFrame {
} }
} }
/// Extra info about values. For example, on the stack.
#[derive(Debug, Clone, Default)]
pub struct ValueExtraInfo {
/// Whether or not the value should be ref counted.
pub ref_counted: bool,
}
/// Contains information passed along during a function's translation and that records: /// Contains information passed along during a function's translation and that records:
/// ///
/// - The current value and control stacks. /// - The current value and control stacks.
@@ -263,6 +270,8 @@ impl FuncTranslationState {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self { Self {
stack: Vec::new(), stack: Vec::new(),
// TODO(reftypes):
//metadata_stack: Vec::new(),
control_stack: Vec::new(), control_stack: Vec::new(),
reachable: true, reachable: true,
globals: HashMap::new(), globals: HashMap::new(),
@@ -300,43 +309,66 @@ impl FuncTranslationState {
); );
} }
/// Push a value. /// Push a value with extra info attached.
pub(crate) fn push1_extra(&mut self, val: (Value, ValueExtraInfo)) {
self.stack.push(val.0);
// TODO(reftypes):
//self.metadata_stack.push(val.1);
}
/// Push a value with default extra info.
pub(crate) fn push1(&mut self, val: Value) { pub(crate) fn push1(&mut self, val: Value) {
self.stack.push(val); self.stack.push(val);
// TODO(reftypes):
//self.metadata_stack.push(ValueExtraInfo::default());
} }
/// Push multiple values. /// Push multiple values.
pub(crate) fn pushn(&mut self, vals: &[Value]) { pub(crate) fn pushn(&mut self, vals: &[Value], _vals_metadata: &[ValueExtraInfo]) {
assert_eq!(vals.len(), _vals_metadata.len());
self.stack.extend_from_slice(vals); self.stack.extend_from_slice(vals);
// TODO(reftypes):
//self.metadata_stack.extend_from_slice(vals_metadata);
} }
/// Pop one value. /// Pop one value.
pub(crate) fn pop1(&mut self) -> Value { pub(crate) fn pop1(&mut self) -> (Value, ValueExtraInfo) {
self.stack let val = self
.stack
.pop() .pop()
.expect("attempted to pop a value from an empty stack") .expect("attempted to pop a value from an empty stack");
let val_metadata = Default::default();
(val, val_metadata)
} }
/// Peek at the top of the stack without popping it. /// Peek at the top of the stack without popping it.
pub(crate) fn peek1(&self) -> Value { pub(crate) fn peek1(&self) -> (Value, ValueExtraInfo) {
*self let val = *self
.stack .stack
.last() .last()
.expect("attempted to peek at a value on an empty stack") .expect("attempted to peek at a value on an empty stack");
let val_metadata = Default::default();
(val, val_metadata)
} }
/// Pop two values. Return them in the order they were pushed. /// Pop two values. Return them in the order they were pushed.
pub(crate) fn pop2(&mut self) -> (Value, Value) { pub(crate) fn pop2(&mut self) -> ((Value, ValueExtraInfo), (Value, ValueExtraInfo)) {
let v2 = self.stack.pop().unwrap(); let v2 = self.pop1();
let v1 = self.stack.pop().unwrap(); let v1 = self.pop1();
(v1, v2) (v1, v2)
} }
/// Pop three values. Return them in the order they were pushed. /// Pop three values. Return them in the order they were pushed.
pub(crate) fn pop3(&mut self) -> (Value, Value, Value) { pub(crate) fn pop3(
let v3 = self.stack.pop().unwrap(); &mut self,
let v2 = self.stack.pop().unwrap(); ) -> (
let v1 = self.stack.pop().unwrap(); (Value, ValueExtraInfo),
(Value, ValueExtraInfo),
(Value, ValueExtraInfo),
) {
let v3 = self.pop1();
let v2 = self.pop1();
let v1 = self.pop1();
(v1, v2, v3) (v1, v2, v3)
} }
@@ -349,7 +381,14 @@ impl FuncTranslationState {
"attempted to access {} values but stack only has {} values", "attempted to access {} values but stack only has {} values",
n, n,
self.stack.len() self.stack.len()
) );
// TODO(reftypes):
/*debug_assert!(
n <= self.metadata_stack.len(),
"attempted to access {} values but stack only has {} values",
n,
self.metadata_stack.len()
);*/
} }
/// Pop the top `n` values on the stack. /// Pop the top `n` values on the stack.
@@ -362,16 +401,25 @@ impl FuncTranslationState {
} }
/// Peek at the top `n` values on the stack in the order they were pushed. /// Peek at the top `n` values on the stack in the order they were pushed.
pub(crate) fn peekn(&self, n: usize) -> &[Value] { pub(crate) fn peekn(&self, n: usize) -> (&[Value], &[ValueExtraInfo]) {
self.ensure_length_is_at_least(n); self.ensure_length_is_at_least(n);
&self.stack[self.stack.len() - n..] let vals = &self.stack[self.stack.len() - n..];
// TODO(reftypes):
let vals_metadata = &[]; //&self.metadata_stack[self.metadata_stack.len() - n..];
(vals, vals_metadata)
} }
/// Peek at the top `n` values on the stack in the order they were pushed. /// Peek at the top `n` values on the stack in the order they were pushed.
pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] { pub(crate) fn peekn_mut(&mut self, n: usize) -> (&mut [Value], &mut [ValueExtraInfo]) {
self.ensure_length_is_at_least(n); self.ensure_length_is_at_least(n);
let len = self.stack.len(); let len = self.stack.len();
&mut self.stack[len - n..] // TODO(reftypes):
//let metadata_len = self.metadata_stack.len();
//assert_eq!(len, metadata_len);
let vals = &mut self.stack[len - n..];
// TODO(reftypes):
let vals_metadata = &mut []; //&mut self.metadata_stack[metadata_len - n..];
(vals, vals_metadata)
} }
/// Push a block on the control stack. /// Push a block on the control stack.

View File

@@ -19,8 +19,8 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use tracing::info; use tracing::info;
use wasmer_compiler::wasmparser; use wasmer_compiler::wasmparser;
use wasmer_compiler::{ use wasmer_compiler::{
wasm_unsupported, MiddlewareBinaryReader, ModuleMiddlewareChain, ModuleTranslationState, wasm_unsupported, wptype_to_type, MiddlewareBinaryReader, ModuleMiddlewareChain,
WasmResult, ModuleTranslationState, WasmResult,
}; };
use wasmer_types::LocalFunctionIndex; use wasmer_types::LocalFunctionIndex;
@@ -77,6 +77,7 @@ impl FuncTranslator {
.middlewares .middlewares
.generate_function_middleware_chain(local_function_index), .generate_function_middleware_chain(local_function_index),
); );
environ.push_params_on_stack(local_function_index);
self.translate_from_reader(module_translation_state, reader, func, environ) self.translate_from_reader(module_translation_state, reader, func, environ)
} }
@@ -211,12 +212,14 @@ fn declare_locals<FE: FuncEnvironment + ?Sized>(
ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)), ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)),
}; };
let wasmer_ty = wptype_to_type(wasm_type).unwrap();
let ty = builder.func.dfg.value_type(zeroval); let ty = builder.func.dfg.value_type(zeroval);
for _ in 0..count { for _ in 0..count {
let local = Variable::new(*next_local); let local = Variable::new(*next_local);
builder.declare_var(local, ty); builder.declare_var(local, ty);
builder.def_var(local, zeroval); builder.def_var(local, zeroval);
builder.set_val_label(zeroval, ValueLabel::new(*next_local)); builder.set_val_label(zeroval, ValueLabel::new(*next_local));
environ.push_local_decl_on_stack(wasmer_ty);
*next_local += 1; *next_local += 1;
} }
Ok(()) Ok(())
@@ -245,6 +248,8 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
environ.after_translate_operator(&op, builder, state)?; environ.after_translate_operator(&op, builder, state)?;
} }
// When returning we drop all values in locals and on the stack.
// The final `End` operator left us in the exit block where we need to manually add a return // The final `End` operator left us in the exit block where we need to manually add a return
// instruction. // instruction.
// //
@@ -253,6 +258,23 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
if state.reachable { if state.reachable {
debug_assert!(builder.is_pristine()); debug_assert!(builder.is_pristine());
if !builder.is_unreachable() { if !builder.is_unreachable() {
environ.translate_drop_locals(builder)?;
let _num_elems_to_drop = state.stack.len() - builder.func.signature.returns.len();
// drop elements on the stack that we're not returning
/*for val in state
.stack
.iter()
.zip(state.metadata_stack.iter())
.take(num_elems_to_drop)
.filter(|(_, metadata)| metadata.ref_counted)
.map(|(val, _)| val)
{
environ.translate_externref_dec(builder.cursor(), *val)?;
}*/
// TODO: look into what `state.reachable` check above does as well as `!builder.is_unreachable`, do we need that too for ref counting?
match environ.return_mode() { match environ.return_mode() {
ReturnMode::NormalReturns => { ReturnMode::NormalReturns => {
let return_types = wasm_param_types(&builder.func.signature.returns, |i| { let return_types = wasm_param_types(&builder.func.signature.returns, |i| {
@@ -269,6 +291,7 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
// Discard any remaining values on the stack. Either we just returned them, // Discard any remaining values on the stack. Either we just returned them,
// or the end of the function is unreachable. // or the end of the function is unreachable.
state.stack.clear(); state.stack.clear();
//state.metadata_stack.clear();
debug_assert!(reader.eof()); debug_assert!(reader.eof());

View File

@@ -140,8 +140,7 @@ impl Abi for Aarch64SystemV {
Type::I32 | Type::F32 => 32, Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => 64, Type::I64 | Type::F64 => 64,
Type::V128 => 128, Type::V128 => 128,
Type::ExternRef => unimplemented!("externref in the llvm backend"), Type::ExternRef | Type::FuncRef => 64, /* pointer */
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
}) })
.collect::<Vec<i32>>(); .collect::<Vec<i32>>();
match sig_returns_bitwidths.as_slice() { match sig_returns_bitwidths.as_slice() {
@@ -285,8 +284,10 @@ impl Abi for Aarch64SystemV {
assert!(value.get_type() == intrinsics.i128_ty.as_basic_type_enum()); assert!(value.get_type() == intrinsics.i128_ty.as_basic_type_enum());
value value
} }
Type::ExternRef => unimplemented!("externref in the llvm backend"), Type::ExternRef | Type::FuncRef => {
Type::FuncRef => unimplemented!("funcref in the llvm backend"), assert!(value.get_type() == intrinsics.funcref_ty.as_basic_type_enum());
value
}
} }
}; };
@@ -322,8 +323,7 @@ impl Abi for Aarch64SystemV {
Type::I32 | Type::F32 => 32, Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => 64, Type::I64 | Type::F64 => 64,
Type::V128 => 128, Type::V128 => 128,
Type::ExternRef => unimplemented!("externref in the llvm backend"), Type::ExternRef | Type::FuncRef => 64, /* pointer */
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
}) })
.collect::<Vec<i32>>(); .collect::<Vec<i32>>();
@@ -420,15 +420,12 @@ impl Abi for Aarch64SystemV {
.results() .results()
.iter() .iter()
.map(|ty| match ty { .map(|ty| match ty {
Type::I32 | Type::F32 => Ok(32), Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => Ok(64), Type::I64 | Type::F64 => 64,
Type::V128 => Ok(128), Type::V128 => 128,
ty => Err(CompileError::Codegen(format!( Type::ExternRef | Type::FuncRef => 64, /* pointer */
"is_sret: unimplemented wasmer_types type {:?}",
ty
))),
}) })
.collect::<Result<Vec<i32>, _>>()?; .collect::<Vec<i32>>();
Ok(!matches!( Ok(!matches!(
func_sig_returns_bitwidths.as_slice(), func_sig_returns_bitwidths.as_slice(),

View File

@@ -92,8 +92,7 @@ impl Abi for X86_64SystemV {
Type::I32 | Type::F32 => 32, Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => 64, Type::I64 | Type::F64 => 64,
Type::V128 => 128, Type::V128 => 128,
Type::ExternRef => unimplemented!("externref in the llvm backend"), Type::ExternRef | Type::FuncRef => 64, /* pointer */
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
}) })
.collect::<Vec<i32>>(); .collect::<Vec<i32>>();
@@ -316,26 +315,7 @@ impl Abi for X86_64SystemV {
); );
builder.build_bitcast(value, intrinsics.f32_ty, "") builder.build_bitcast(value, intrinsics.f32_ty, "")
} }
Type::I64 => { _ => panic!("should only be called to repack 32-bit values"),
assert!(
value.get_type() == intrinsics.i64_ty.as_basic_type_enum()
|| value.get_type() == intrinsics.f64_ty.as_basic_type_enum()
);
builder.build_bitcast(value, intrinsics.i64_ty, "")
}
Type::F64 => {
assert!(
value.get_type() == intrinsics.i64_ty.as_basic_type_enum()
|| value.get_type() == intrinsics.f64_ty.as_basic_type_enum()
);
builder.build_bitcast(value, intrinsics.f64_ty, "")
}
Type::V128 => {
assert!(value.get_type() == intrinsics.i128_ty.as_basic_type_enum());
value
}
Type::ExternRef => unimplemented!("externref in the llvm backend"),
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
} }
}; };
@@ -365,8 +345,7 @@ impl Abi for X86_64SystemV {
Type::I32 | Type::F32 => 32, Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => 64, Type::I64 | Type::F64 => 64,
Type::V128 => 128, Type::V128 => 128,
Type::ExternRef => unimplemented!("externref in the llvm backend"), Type::ExternRef | Type::FuncRef => 64, /* pointer */
Type::FuncRef => unimplemented!("funcref in the llvm backend"),
}) })
.collect::<Vec<i32>>(); .collect::<Vec<i32>>();
@@ -475,15 +454,12 @@ impl Abi for X86_64SystemV {
.results() .results()
.iter() .iter()
.map(|ty| match ty { .map(|ty| match ty {
Type::I32 | Type::F32 => Ok(32), Type::I32 | Type::F32 => 32,
Type::I64 | Type::F64 => Ok(64), Type::I64 | Type::F64 => 64,
Type::V128 => Ok(128), Type::V128 => 128,
ty => Err(CompileError::Codegen(format!( Type::ExternRef | Type::FuncRef => 64, /* pointer */
"is_sret: unimplemented wasmer_types type {:?}",
ty
))),
}) })
.collect::<Result<Vec<i32>, _>>()?; .collect::<Vec<i32>>();
Ok(!matches!( Ok(!matches!(
func_sig_returns_bitwidths.as_slice(), func_sig_returns_bitwidths.as_slice(),

View File

@@ -57,10 +57,7 @@ impl SymbolRegistry for ShortNames {
return None; return None;
} }
let (ty, idx) = name.split_at(1); let (ty, idx) = name.split_at(1);
let idx = match idx.parse::<u32>() { let idx = idx.parse::<u32>().ok()?;
Ok(v) => v,
Err(_) => return None,
};
match ty.chars().next().unwrap() { match ty.chars().next().unwrap() {
'f' => Some(Symbol::LocalFunction(LocalFunctionIndex::from_u32(idx))), 'f' => Some(Symbol::LocalFunction(LocalFunctionIndex::from_u32(idx))),
's' => Some(Symbol::Section(SectionIndex::from_u32(idx))), 's' => Some(Symbol::Section(SectionIndex::from_u32(idx))),

View File

@@ -54,16 +54,66 @@ where
{ {
// TODO: use perfect hash function? // TODO: use perfect hash function?
let mut libcalls = HashMap::new(); let mut libcalls = HashMap::new();
libcalls.insert("wasmer_raise_trap".to_string(), LibCall::RaiseTrap);
libcalls.insert("truncf".to_string(), LibCall::TruncF32);
libcalls.insert("trunc".to_string(), LibCall::TruncF64);
libcalls.insert("ceilf".to_string(), LibCall::CeilF32); libcalls.insert("ceilf".to_string(), LibCall::CeilF32);
libcalls.insert("ceil".to_string(), LibCall::CeilF64); libcalls.insert("ceil".to_string(), LibCall::CeilF64);
libcalls.insert("floorf".to_string(), LibCall::FloorF32); libcalls.insert("floorf".to_string(), LibCall::FloorF32);
libcalls.insert("floor".to_string(), LibCall::FloorF64); libcalls.insert("floor".to_string(), LibCall::FloorF64);
libcalls.insert("nearbyintf".to_string(), LibCall::NearestF32); libcalls.insert("nearbyintf".to_string(), LibCall::NearestF32);
libcalls.insert("nearbyint".to_string(), LibCall::NearestF64); libcalls.insert("nearbyint".to_string(), LibCall::NearestF64);
libcalls.insert("wasmer_probestack".to_string(), LibCall::Probestack); libcalls.insert("truncf".to_string(), LibCall::TruncF32);
libcalls.insert("trunc".to_string(), LibCall::TruncF64);
libcalls.insert("wasmer_vm_f32_ceil".to_string(), LibCall::CeilF32);
libcalls.insert("wasmer_vm_f64_ceil".to_string(), LibCall::CeilF64);
libcalls.insert("wasmer_vm_f32_floor".to_string(), LibCall::FloorF32);
libcalls.insert("wasmer_vm_f64_floor".to_string(), LibCall::FloorF64);
libcalls.insert("wasmer_vm_f32_nearest".to_string(), LibCall::NearestF32);
libcalls.insert("wasmer_vm_f64_nearest".to_string(), LibCall::NearestF64);
libcalls.insert("wasmer_vm_f32_trunc".to_string(), LibCall::TruncF32);
libcalls.insert("wasmer_vm_f64_trunc".to_string(), LibCall::TruncF64);
libcalls.insert("wasmer_vm_memory32_size".to_string(), LibCall::Memory32Size);
libcalls.insert(
"wasmer_vm_imported_memory32_size".to_string(),
LibCall::ImportedMemory32Size,
);
libcalls.insert("wasmer_vm_table_copy".to_string(), LibCall::TableCopy);
libcalls.insert("wasmer_vm_table_init".to_string(), LibCall::TableInit);
libcalls.insert("wasmer_vm_table_fill".to_string(), LibCall::TableFill);
libcalls.insert("wasmer_vm_table_size".to_string(), LibCall::TableSize);
libcalls.insert(
"wasmer_vm_imported_table_size".to_string(),
LibCall::ImportedTableSize,
);
libcalls.insert("wasmer_vm_table_get".to_string(), LibCall::TableGet);
libcalls.insert(
"wasmer_vm_imported_table_get".to_string(),
LibCall::ImportedTableGet,
);
libcalls.insert("wasmer_vm_table_set".to_string(), LibCall::TableSet);
libcalls.insert(
"wasmer_vm_imported_table_set".to_string(),
LibCall::ImportedTableSet,
);
libcalls.insert("wasmer_vm_table_grow".to_string(), LibCall::TableGrow);
libcalls.insert(
"wasmer_vm_imported_table_grow".to_string(),
LibCall::ImportedTableGrow,
);
libcalls.insert("wasmer_vm_func_ref".to_string(), LibCall::FuncRef);
libcalls.insert("wasmer_vm_elem_drop".to_string(), LibCall::ElemDrop);
libcalls.insert("wasmer_vm_memory32_copy".to_string(), LibCall::Memory32Copy);
libcalls.insert(
"wasmer_vm_imported_memory32_copy".to_string(),
LibCall::ImportedMemory32Copy,
);
libcalls.insert("wasmer_vm_memory32_fill".to_string(), LibCall::Memory32Fill);
libcalls.insert(
"wasmer_vm_imported_memory32_fill".to_string(),
LibCall::ImportedMemory32Fill,
);
libcalls.insert("wasmer_vm_memory32_init".to_string(), LibCall::Memory32Init);
libcalls.insert("wasmer_vm_data_drop".to_string(), LibCall::DataDrop);
libcalls.insert("wasmer_vm_raise_trap".to_string(), LibCall::RaiseTrap);
libcalls.insert("wasmer_vm_probestack".to_string(), LibCall::Probestack);
let elf = goblin::elf::Elf::parse(&contents).map_err(map_goblin_err)?; let elf = goblin::elf::Elf::parse(&contents).map_err(map_goblin_err)?;
let get_section_name = |section: &goblin::elf::section_header::SectionHeader| { let get_section_name = |section: &goblin::elf::section_header::SectionHeader| {

View File

@@ -2187,47 +2187,6 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
); );
let func_index = self.state.pop1()?.into_int_value(); let func_index = self.state.pop1()?.into_int_value();
// We assume the table has the `anyfunc` element type.
let casted_table_base = self.builder.build_pointer_cast(
table_base,
self.intrinsics.anyfunc_ty.ptr_type(AddressSpace::Generic),
"casted_table_base",
);
let anyfunc_struct_ptr = unsafe {
self.builder.build_in_bounds_gep(
casted_table_base,
&[func_index],
"anyfunc_struct_ptr",
)
};
// Load things from the anyfunc data structure.
let (func_ptr, found_dynamic_sigindex, ctx_ptr) = (
self.builder
.build_load(
self.builder
.build_struct_gep(anyfunc_struct_ptr, 0, "func_ptr_ptr")
.unwrap(),
"func_ptr",
)
.into_pointer_value(),
self.builder
.build_load(
self.builder
.build_struct_gep(anyfunc_struct_ptr, 1, "sigindex_ptr")
.unwrap(),
"sigindex",
)
.into_int_value(),
self.builder.build_load(
self.builder
.build_struct_gep(anyfunc_struct_ptr, 2, "ctx_ptr_ptr")
.unwrap(),
"ctx_ptr",
),
);
let truncated_table_bounds = self.builder.build_int_truncate( let truncated_table_bounds = self.builder.build_int_truncate(
table_bound, table_bound,
self.intrinsics.i32_ty, self.intrinsics.i32_ty,
@@ -2280,8 +2239,85 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
self.builder.build_unreachable(); self.builder.build_unreachable();
self.builder.position_at_end(in_bounds_continue_block); self.builder.position_at_end(in_bounds_continue_block);
// We assume the table has the `funcref` (pointer to `anyfunc`)
// element type.
let casted_table_base = self.builder.build_pointer_cast(
table_base,
self.intrinsics.funcref_ty.ptr_type(AddressSpace::Generic),
"casted_table_base",
);
let funcref_ptr = unsafe {
self.builder.build_in_bounds_gep(
casted_table_base,
&[func_index],
"funcref_ptr",
)
};
// a funcref (pointer to `anyfunc`)
let anyfunc_struct_ptr = self
.builder
.build_load(funcref_ptr, "anyfunc_struct_ptr")
.into_pointer_value();
// trap if we're trying to call a null funcref
{
let funcref_not_null = self
.builder
.build_is_not_null(anyfunc_struct_ptr, "null funcref check");
let funcref_continue_deref_block = self
.context
.append_basic_block(self.function, "funcref_continue deref_block");
let funcref_is_null_block = self
.context
.append_basic_block(self.function, "funcref_is_null_block");
self.builder.build_conditional_branch(
funcref_not_null,
funcref_continue_deref_block,
funcref_is_null_block,
);
self.builder.position_at_end(funcref_is_null_block);
self.builder.build_call(
self.intrinsics.throw_trap,
&[self.intrinsics.trap_call_indirect_null],
"throw",
);
self.builder.build_unreachable();
self.builder.position_at_end(funcref_continue_deref_block);
}
// Load things from the anyfunc data structure.
let (func_ptr, found_dynamic_sigindex, ctx_ptr) = (
self.builder
.build_load(
self.builder
.build_struct_gep(anyfunc_struct_ptr, 0, "func_ptr_ptr")
.unwrap(),
"func_ptr",
)
.into_pointer_value(),
self.builder
.build_load(
self.builder
.build_struct_gep(anyfunc_struct_ptr, 1, "sigindex_ptr")
.unwrap(),
"sigindex",
)
.into_int_value(),
self.builder.build_load(
self.builder
.build_struct_gep(anyfunc_struct_ptr, 2, "ctx_ptr_ptr")
.unwrap(),
"ctx_ptr",
),
);
// Next, check if the table element is initialized. // Next, check if the table element is initialized.
// TODO: we may not need this check anymore
let elem_initialized = self.builder.build_is_not_null(func_ptr, ""); let elem_initialized = self.builder.build_is_not_null(func_ptr, "");
// Next, check if the signature id is correct. // Next, check if the signature id is correct.
@@ -3118,8 +3154,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let v2 = self.builder.build_and(v2, mask, ""); let v2 = self.builder.build_and(v2, mask, "");
let lhs = self.builder.build_right_shift(v1, v2, false, ""); let lhs = self.builder.build_right_shift(v1, v2, false, "");
let rhs = { let rhs = {
let int_width = self.intrinsics.i64_ty.const_int(64 as u64, false); let negv2 = self.builder.build_int_neg(v2, "");
let rhs = self.builder.build_int_sub(int_width, v2, ""); let rhs = self.builder.build_and(negv2, mask, "");
self.builder.build_left_shift(v1, rhs, "") self.builder.build_left_shift(v1, rhs, "")
}; };
let res = self.builder.build_or(lhs, rhs, ""); let res = self.builder.build_or(lhs, rhs, "");
@@ -9350,6 +9386,215 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly); size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly);
self.state.push1(size.try_as_basic_value().left().unwrap()); self.state.push1(size.try_as_basic_value().left().unwrap());
} }
/***************************
* Reference types.
* https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md
***************************/
Operator::RefNull { ty } => {
let ty = wptype_to_type(ty).map_err(to_compile_error)?;
let ty = type_to_llvm(self.intrinsics, ty)?;
self.state.push1(ty.const_zero());
}
Operator::RefIsNull => {
let value = self.state.pop1()?.into_pointer_value();
let is_null = self.builder.build_is_null(value, "");
let is_null = self
.builder
.build_int_z_extend(is_null, self.intrinsics.i32_ty, "");
self.state.push1(is_null);
}
Operator::RefFunc { function_index } => {
let index = self
.intrinsics
.i32_ty
.const_int(function_index.into(), false)
.as_basic_value_enum();
let value = self
.builder
.build_call(self.intrinsics.func_ref, &[self.ctx.basic(), index], "")
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(value);
}
Operator::TableGet { table } => {
let table_index = self
.intrinsics
.i32_ty
.const_int(table.into(), false)
.as_basic_value_enum();
let elem = self.state.pop1()?;
let table_get = if let Some(_) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
self.intrinsics.table_get
} else {
self.intrinsics.imported_table_get
};
let value = self
.builder
.build_call(table_get, &[self.ctx.basic(), table_index, elem], "")
.try_as_basic_value()
.left()
.unwrap();
let value = self.builder.build_bitcast(
value,
type_to_llvm(
self.intrinsics,
self.wasm_module
.tables
.get(TableIndex::from_u32(table))
.unwrap()
.ty,
)?,
"",
);
self.state.push1(value);
}
Operator::TableSet { table } => {
let table_index = self
.intrinsics
.i32_ty
.const_int(table.into(), false)
.as_basic_value_enum();
let (elem, value) = self.state.pop2()?;
let value = self
.builder
.build_bitcast(value, self.intrinsics.anyref_ty, "");
let table_set = if let Some(_) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
self.intrinsics.table_set
} else {
self.intrinsics.imported_table_set
};
self.builder.build_call(
table_set,
&[self.ctx.basic(), table_index, elem, value],
"",
);
}
Operator::TableCopy {
dst_table,
src_table,
} => {
let (dst, src, len) = self.state.pop3()?;
let dst_table = self
.intrinsics
.i32_ty
.const_int(dst_table as u64, false)
.as_basic_value_enum();
let src_table = self
.intrinsics
.i32_ty
.const_int(src_table as u64, false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.table_copy,
&[self.ctx.basic(), dst_table, src_table, dst, src, len],
"",
);
}
Operator::TableInit { segment, table } => {
let (dst, src, len) = self.state.pop3()?;
let segment = self
.intrinsics
.i32_ty
.const_int(segment as u64, false)
.as_basic_value_enum();
let table = self
.intrinsics
.i32_ty
.const_int(table as u64, false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.table_init,
&[self.ctx.basic(), table, segment, dst, src, len],
"",
);
}
Operator::ElemDrop { segment } => {
let segment = self
.intrinsics
.i32_ty
.const_int(segment as u64, false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.elem_drop,
&[self.ctx.basic(), segment],
"",
);
}
Operator::TableFill { table } => {
let table = self
.intrinsics
.i32_ty
.const_int(table as u64, false)
.as_basic_value_enum();
let (start, elem, len) = self.state.pop3()?;
let elem = self
.builder
.build_bitcast(elem, self.intrinsics.anyref_ty, "");
self.builder.build_call(
self.intrinsics.table_fill,
&[self.ctx.basic(), table, start, elem, len],
"",
);
}
Operator::TableGrow { table } => {
let (elem, delta) = self.state.pop2()?;
let elem = self
.builder
.build_bitcast(elem, self.intrinsics.anyref_ty, "");
let (table_grow, table_index) = if let Some(local_table_index) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
(self.intrinsics.table_grow, local_table_index.as_u32())
} else {
(self.intrinsics.imported_table_grow, table)
};
let table_index = self
.intrinsics
.i32_ty
.const_int(table_index as u64, false)
.as_basic_value_enum();
let size = self
.builder
.build_call(
table_grow,
&[self.ctx.basic(), elem, delta, table_index],
"",
)
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(size);
}
Operator::TableSize { table } => {
let (table_size, table_index) = if let Some(local_table_index) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
(self.intrinsics.table_size, local_table_index.as_u32())
} else {
(self.intrinsics.imported_table_size, table)
};
let table_index = self
.intrinsics
.i32_ty
.const_int(table_index as u64, false)
.as_basic_value_enum();
let size = self
.builder
.build_call(table_size, &[self.ctx.basic(), table_index], "")
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(size);
}
_ => { _ => {
return Err(CompileError::Codegen(format!( return Err(CompileError::Codegen(format!(
"Operator {:?} unimplemented", "Operator {:?} unimplemented",

View File

@@ -39,10 +39,8 @@ pub fn type_to_llvm_ptr<'ctx>(
Type::F32 => Ok(intrinsics.f32_ptr_ty), Type::F32 => Ok(intrinsics.f32_ptr_ty),
Type::F64 => Ok(intrinsics.f64_ptr_ty), Type::F64 => Ok(intrinsics.f64_ptr_ty),
Type::V128 => Ok(intrinsics.i128_ptr_ty), Type::V128 => Ok(intrinsics.i128_ptr_ty),
ty => Err(CompileError::Codegen(format!( Type::FuncRef => Ok(intrinsics.funcref_ty.ptr_type(AddressSpace::Generic)),
"type_to_llvm: unimplemented wasmer_types type {:?}", Type::ExternRef => Ok(intrinsics.externref_ty.ptr_type(AddressSpace::Generic)),
ty
))),
} }
} }
@@ -56,10 +54,8 @@ pub fn type_to_llvm<'ctx>(
Type::F32 => Ok(intrinsics.f32_ty.as_basic_type_enum()), Type::F32 => Ok(intrinsics.f32_ty.as_basic_type_enum()),
Type::F64 => Ok(intrinsics.f64_ty.as_basic_type_enum()), Type::F64 => Ok(intrinsics.f64_ty.as_basic_type_enum()),
Type::V128 => Ok(intrinsics.i128_ty.as_basic_type_enum()), Type::V128 => Ok(intrinsics.i128_ty.as_basic_type_enum()),
ty => Err(CompileError::Codegen(format!( Type::FuncRef => Ok(intrinsics.funcref_ty.as_basic_type_enum()),
"type_to_llvm: unimplemented wasmer_types type {:?}", Type::ExternRef => Ok(intrinsics.externref_ty.as_basic_type_enum()),
ty
))),
} }
} }
@@ -147,6 +143,10 @@ pub struct Intrinsics<'ctx> {
pub anyfunc_ty: StructType<'ctx>, pub anyfunc_ty: StructType<'ctx>,
pub funcref_ty: PointerType<'ctx>,
pub externref_ty: PointerType<'ctx>,
pub anyref_ty: PointerType<'ctx>,
pub i1_zero: IntValue<'ctx>, pub i1_zero: IntValue<'ctx>,
pub i8_zero: IntValue<'ctx>, pub i8_zero: IntValue<'ctx>,
pub i32_zero: IntValue<'ctx>, pub i32_zero: IntValue<'ctx>,
@@ -167,11 +167,25 @@ pub struct Intrinsics<'ctx> {
pub trap_unaligned_atomic: BasicValueEnum<'ctx>, pub trap_unaligned_atomic: BasicValueEnum<'ctx>,
pub trap_table_access_oob: BasicValueEnum<'ctx>, pub trap_table_access_oob: BasicValueEnum<'ctx>,
// VM intrinsics.
pub throw_trap: FunctionValue<'ctx>,
pub experimental_stackmap: FunctionValue<'ctx>, pub experimental_stackmap: FunctionValue<'ctx>,
// VM libcalls.
pub table_copy: FunctionValue<'ctx>,
pub table_init: FunctionValue<'ctx>,
pub table_fill: FunctionValue<'ctx>,
pub table_size: FunctionValue<'ctx>,
pub imported_table_size: FunctionValue<'ctx>,
pub table_get: FunctionValue<'ctx>,
pub imported_table_get: FunctionValue<'ctx>,
pub table_set: FunctionValue<'ctx>,
pub imported_table_set: FunctionValue<'ctx>,
pub table_grow: FunctionValue<'ctx>,
pub imported_table_grow: FunctionValue<'ctx>,
pub func_ref: FunctionValue<'ctx>,
pub elem_drop: FunctionValue<'ctx>,
pub throw_trap: FunctionValue<'ctx>,
// VM builtins.
pub vmfunction_import_ptr_ty: PointerType<'ctx>, pub vmfunction_import_ptr_ty: PointerType<'ctx>,
pub vmfunction_import_body_element: u32, pub vmfunction_import_body_element: u32,
pub vmfunction_import_vmctx_element: u32, pub vmfunction_import_vmctx_element: u32,
@@ -185,6 +199,7 @@ pub struct Intrinsics<'ctx> {
pub memory32_size_ptr_ty: PointerType<'ctx>, pub memory32_size_ptr_ty: PointerType<'ctx>,
pub imported_memory32_size_ptr_ty: PointerType<'ctx>, pub imported_memory32_size_ptr_ty: PointerType<'ctx>,
// Pointer to the VM.
pub ctx_ptr_ty: PointerType<'ctx>, pub ctx_ptr_ty: PointerType<'ctx>,
} }
@@ -251,6 +266,9 @@ impl<'ctx> Intrinsics<'ctx> {
], ],
false, false,
); );
let funcref_ty = anyfunc_ty.ptr_type(AddressSpace::Generic);
let externref_ty = funcref_ty;
let anyref_ty = i8_ptr_ty;
let ret_i8x16_take_i8x16_i8x16 = i8x16_ty.fn_type(&[i8x16_ty_basic, i8x16_ty_basic], false); let ret_i8x16_take_i8x16_i8x16 = i8x16_ty.fn_type(&[i8x16_ty_basic, i8x16_ty_basic], false);
let ret_i16x8_take_i16x8_i16x8 = i16x8_ty.fn_type(&[i16x8_ty_basic, i16x8_ty_basic], false); let ret_i16x8_take_i16x8_i16x8 = i16x8_ty.fn_type(&[i16x8_ty_basic, i16x8_ty_basic], false);
@@ -369,7 +387,7 @@ impl<'ctx> Intrinsics<'ctx> {
), ),
readonly: context readonly: context
.create_enum_attribute(Attribute::get_named_enum_kind_id("readonly"), 0), .create_enum_attribute(Attribute::get_named_enum_kind_id("readonly"), 0),
stack_probe: context.create_string_attribute("probe-stack", "wasmer_probestack"), stack_probe: context.create_string_attribute("probe-stack", "wasmer_vm_probestack"),
void_ty, void_ty,
i1_ty, i1_ty,
@@ -399,6 +417,10 @@ impl<'ctx> Intrinsics<'ctx> {
anyfunc_ty, anyfunc_ty,
funcref_ty,
externref_ty,
anyref_ty,
i1_zero, i1_zero,
i8_zero, i8_zero,
i32_zero, i32_zero,
@@ -437,12 +459,6 @@ impl<'ctx> Intrinsics<'ctx> {
.const_int(TrapCode::TableAccessOutOfBounds as _, false) .const_int(TrapCode::TableAccessOutOfBounds as _, false)
.as_basic_value_enum(), .as_basic_value_enum(),
// VM intrinsics.
throw_trap: module.add_function(
"wasmer_raise_trap",
void_ty.fn_type(&[i32_ty_basic], false),
None,
),
experimental_stackmap: module.add_function( experimental_stackmap: module.add_function(
"llvm.experimental.stackmap", "llvm.experimental.stackmap",
void_ty.fn_type( void_ty.fn_type(
@@ -455,6 +471,145 @@ impl<'ctx> Intrinsics<'ctx> {
None, None,
), ),
// VM libcalls.
table_copy: module.add_function(
"wasmer_vm_table_copy",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
table_init: module.add_function(
"wasmer_vm_table_init",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
table_fill: module.add_function(
"wasmer_vm_table_fill",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
anyref_ty.as_basic_type_enum(),
i32_ty_basic,
],
false,
),
None,
),
table_size: module.add_function(
"wasmer_vm_table_size",
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false),
None,
),
imported_table_size: module.add_function(
"wasmer_vm_imported_table_size",
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false),
None,
),
table_get: module.add_function(
"wasmer_vm_table_get",
anyref_ty.fn_type(
&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic],
false,
),
None,
),
imported_table_get: module.add_function(
"wasmer_vm_imported_table_get",
anyref_ty.fn_type(
&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic],
false,
),
None,
),
table_set: module.add_function(
"wasmer_vm_table_set",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
anyref_ty.as_basic_type_enum(),
],
false,
),
None,
),
imported_table_set: module.add_function(
"wasmer_vm_imported_table_set",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
anyref_ty.as_basic_type_enum(),
],
false,
),
None,
),
table_grow: module.add_function(
"wasmer_vm_table_grow",
i32_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
anyref_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
imported_table_grow: module.add_function(
"wasmer_vm_imported_table_grow",
i32_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
anyref_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
func_ref: module.add_function(
"wasmer_vm_func_ref",
funcref_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false),
None,
),
elem_drop: module.add_function(
"wasmer_vm_elem_drop",
void_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false),
None,
),
throw_trap: module.add_function(
"wasmer_vm_raise_trap",
void_ty.fn_type(&[i32_ty_basic], false),
None,
),
vmfunction_import_ptr_ty: context vmfunction_import_ptr_ty: context
.struct_type(&[i8_ptr_ty_basic, i8_ptr_ty_basic], false) .struct_type(&[i8_ptr_ty_basic, i8_ptr_ty_basic], false)
.ptr_type(AddressSpace::Generic), .ptr_type(AddressSpace::Generic),
@@ -490,13 +645,14 @@ impl<'ctx> Intrinsics<'ctx> {
ctx_ptr_ty, ctx_ptr_ty,
}; };
// TODO: mark vmctx args as nofree, align 16, dereferenceable(?)
let noreturn = let noreturn =
context.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 0); context.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 0);
intrinsics intrinsics
.throw_trap .throw_trap
.add_attribute(AttributeLoc::Function, noreturn); .add_attribute(AttributeLoc::Function, noreturn);
intrinsics
.func_ref
.add_attribute(AttributeLoc::Function, intrinsics.readonly);
intrinsics intrinsics
} }

View File

@@ -315,6 +315,22 @@ impl<'ctx> State<'ctx> {
Ok((v1, v2)) Ok((v1, v2))
} }
pub fn pop3(
&mut self,
) -> Result<
(
BasicValueEnum<'ctx>,
BasicValueEnum<'ctx>,
BasicValueEnum<'ctx>,
),
CompileError,
> {
let v3 = self.pop1()?;
let v2 = self.pop1()?;
let v1 = self.pop1()?;
Ok((v1, v2, v3))
}
pub fn pop3_extra( pub fn pop3_extra(
&mut self, &mut self,
) -> Result< ) -> Result<

View File

@@ -186,20 +186,14 @@ trait PopMany<T> {
impl<T> PopMany<T> for Vec<T> { impl<T> PopMany<T> for Vec<T> {
fn peek1(&self) -> Result<&T, CodegenError> { fn peek1(&self) -> Result<&T, CodegenError> {
match self.last() { self.last().ok_or_else(|| CodegenError {
Some(x) => Ok(x), message: "peek1() expects at least 1 element".into(),
None => Err(CodegenError { })
message: "peek1() expects at least 1 element".into(),
}),
}
} }
fn pop1(&mut self) -> Result<T, CodegenError> { fn pop1(&mut self) -> Result<T, CodegenError> {
match self.pop() { self.pop().ok_or_else(|| CodegenError {
Some(x) => Ok(x), message: "pop1() expects at least 1 element".into(),
None => Err(CodegenError { })
message: "pop1() expects at least 1 element".into(),
}),
}
} }
fn pop2(&mut self) -> Result<(T, T), CodegenError> { fn pop2(&mut self) -> Result<(T, T), CodegenError> {
if self.len() < 2 { if self.len() < 2 {
@@ -5247,11 +5241,8 @@ impl<'a> FuncGen<'a> {
} }
} }
Operator::CallIndirect { index, table_index } => { Operator::CallIndirect { index, table_index } => {
if table_index != 0 { // TODO: removed restriction on always being table idx 0;
return Err(CodegenError { // does any code depend on this?
message: "CallIndirect: table_index is not 0".to_string(),
});
}
let table_index = TableIndex::new(table_index as _); let table_index = TableIndex::new(table_index as _);
let index = SignatureIndex::new(index as usize); let index = SignatureIndex::new(index as usize);
let sig = self.module.signatures.get(index).unwrap(); let sig = self.module.signatures.get(index).unwrap();
@@ -5341,15 +5332,25 @@ impl<'a> FuncGen<'a> {
.emit_jmp(Condition::BelowEqual, self.special_labels.table_access_oob); .emit_jmp(Condition::BelowEqual, self.special_labels.table_access_oob);
self.assembler self.assembler
.emit_mov(Size::S32, func_index, Location::GPR(table_count)); .emit_mov(Size::S32, func_index, Location::GPR(table_count));
self.assembler.emit_imul_imm32_gpr64( self.assembler
self.vmoffsets.size_of_vmcaller_checked_anyfunc() as u32, .emit_imul_imm32_gpr64(self.vmoffsets.size_of_vm_funcref() as u32, table_count);
table_count,
);
self.assembler.emit_add( self.assembler.emit_add(
Size::S64, Size::S64,
Location::GPR(table_base), Location::GPR(table_base),
Location::GPR(table_count), Location::GPR(table_count),
); );
// deref the table to get a VMFuncRef
self.assembler.emit_mov(
Size::S64,
Location::Memory(table_count, self.vmoffsets.vm_funcref_anyfunc_ptr() as i32),
Location::GPR(table_count),
);
// Trap if the FuncRef is null
self.assembler
.emit_cmp(Size::S64, Location::Imm32(0), Location::GPR(table_count));
self.assembler
.emit_jmp(Condition::Equal, self.special_labels.indirect_call_null);
self.assembler.emit_mov( self.assembler.emit_mov(
Size::S64, Size::S64,
Location::Memory( Location::Memory(
@@ -5359,18 +5360,6 @@ impl<'a> FuncGen<'a> {
Location::GPR(sigidx), Location::GPR(sigidx),
); );
// Trap if the current table entry is null.
self.assembler.emit_cmp(
Size::S64,
Location::Imm32(0),
Location::Memory(
table_count,
(self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize) as i32,
),
);
self.assembler
.emit_jmp(Condition::Equal, self.special_labels.indirect_call_null);
// Trap if signature mismatches. // Trap if signature mismatches.
self.assembler.emit_cmp( self.assembler.emit_cmp(
Size::S32, Size::S32,
@@ -8161,6 +8150,351 @@ impl<'a> FuncGen<'a> {
self.assembler.emit_pop(Size::S64, Location::GPR(value)); self.assembler.emit_pop(Size::S64, Location::GPR(value));
self.machine.release_temp_gpr(compare); self.machine.release_temp_gpr(compare);
} }
Operator::RefNull { .. } => {
self.value_stack.push(Location::Imm64(0));
self.machine
.state
.wasm_stack
.push(WasmAbstractValue::Const(0));
}
Operator::RefFunc { function_index } => {
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_func_ref_index())
as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: unclear if we need this? check other new insts with no stack ops
// self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, func_index] -> funcref
iter::once(Location::Imm32(function_index as u32)),
)?;
let ret = self.machine.acquire_locations(
&mut self.assembler,
&[(
WpType::FuncRef,
MachineValue::WasmStack(self.value_stack.len()),
)],
false,
)[0];
self.value_stack.push(ret);
self.assembler
.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
}
Operator::RefIsNull => {
self.emit_cmpop_i64_dynamic_b(Condition::Equal, Location::Imm64(0))?;
}
Operator::TableSet { table: index } => {
let table_index = TableIndex::new(index as _);
let value = self.value_stack.pop().unwrap();
let index = self.value_stack.pop().unwrap();
// double check this does what I think it does
self.machine.release_locations_only_regs(&[value, index]);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets.vmctx_builtin_function(
if self.module.local_table_index(table_index).is_some() {
VMBuiltinFunctionIndex::get_table_set_index()
} else {
VMBuiltinFunctionIndex::get_imported_table_set_index()
},
) as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: should this be 2?
self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, table_index, elem_index, reftype]
[Location::Imm32(table_index.index() as u32), index, value]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[index, value]);
}
Operator::TableGet { table: index } => {
let table_index = TableIndex::new(index as _);
let index = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[index]);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets.vmctx_builtin_function(
if self.module.local_table_index(table_index).is_some() {
VMBuiltinFunctionIndex::get_table_get_index()
} else {
VMBuiltinFunctionIndex::get_imported_table_get_index()
},
) as i32,
),
Location::GPR(GPR::RAX),
);
self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, table_index, elem_index] -> reftype
[Location::Imm32(table_index.index() as u32), index]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[index]);
let ret = self.machine.acquire_locations(
&mut self.assembler,
&[(
WpType::FuncRef,
MachineValue::WasmStack(self.value_stack.len()),
)],
false,
)[0];
self.value_stack.push(ret);
self.assembler
.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
}
Operator::TableSize { table: index } => {
let table_index = TableIndex::new(index as _);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets.vmctx_builtin_function(
if self.module.local_table_index(table_index).is_some() {
VMBuiltinFunctionIndex::get_table_size_index()
} else {
VMBuiltinFunctionIndex::get_imported_table_size_index()
},
) as i32,
),
Location::GPR(GPR::RAX),
);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, table_index] -> i32
iter::once(Location::Imm32(table_index.index() as u32)),
)?;
let ret = self.machine.acquire_locations(
&mut self.assembler,
&[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))],
false,
)[0];
self.value_stack.push(ret);
self.assembler
.emit_mov(Size::S32, Location::GPR(GPR::RAX), ret);
}
Operator::TableGrow { table: index } => {
let table_index = TableIndex::new(index as _);
let delta = self.value_stack.pop().unwrap();
let init_value = self.value_stack.pop().unwrap();
self.machine
.release_locations_only_regs(&[delta, init_value]);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets.vmctx_builtin_function(
if self.module.local_table_index(table_index).is_some() {
VMBuiltinFunctionIndex::get_table_grow_index()
} else {
VMBuiltinFunctionIndex::get_imported_table_get_index()
},
) as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: should this be 2?
self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, init_value, delta, table_index] -> u32
[
init_value,
delta,
Location::Imm32(table_index.index() as u32),
]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[init_value, delta]);
let ret = self.machine.acquire_locations(
&mut self.assembler,
&[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))],
false,
)[0];
self.value_stack.push(ret);
self.assembler
.emit_mov(Size::S32, Location::GPR(GPR::RAX), ret);
}
Operator::TableCopy {
dst_table,
src_table,
} => {
let len = self.value_stack.pop().unwrap();
let src = self.value_stack.pop().unwrap();
let dest = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[len, src, dest]);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_table_copy_index())
as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: should this be 3?
self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, dst_table_index, src_table_index, dst, src, len]
[
Location::Imm32(dst_table),
Location::Imm32(src_table),
dest,
src,
len,
]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[dest, src, len]);
}
Operator::TableFill { table } => {
let len = self.value_stack.pop().unwrap();
let val = self.value_stack.pop().unwrap();
let dest = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[len, val, dest]);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_table_fill_index())
as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: should this be 3?
self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, table_index, start_idx, item, len]
[Location::Imm32(table), dest, val, len].iter().cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[dest, val, len]);
}
Operator::TableInit { segment, table } => {
let len = self.value_stack.pop().unwrap();
let src = self.value_stack.pop().unwrap();
let dest = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[len, src, dest]);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_table_init_index())
as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: should this be 3?
self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, table_index, elem_index, dst, src, len]
[
Location::Imm32(table),
Location::Imm32(segment),
dest,
src,
len,
]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[dest, src, len]);
}
Operator::ElemDrop { segment } => {
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_elem_drop_index())
as i32,
),
Location::GPR(GPR::RAX),
);
// TODO: do we need this?
//self.machine.release_locations_only_osr_state(1);
self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, elem_index]
[Location::Imm32(segment)].iter().cloned(),
)?;
}
_ => { _ => {
return Err(CodegenError { return Err(CodegenError {
message: format!("not yet implemented: {:?}", op), message: format!("not yet implemented: {:?}", op),

View File

@@ -156,7 +156,8 @@ impl Machine {
let loc = match *ty { let loc = match *ty {
WpType::F32 | WpType::F64 => self.pick_xmm().map(Location::XMM), WpType::F32 | WpType::F64 => self.pick_xmm().map(Location::XMM),
WpType::I32 | WpType::I64 => self.pick_gpr().map(Location::GPR), WpType::I32 | WpType::I64 => self.pick_gpr().map(Location::GPR),
_ => unreachable!(), WpType::FuncRef | WpType::ExternRef => self.pick_gpr().map(Location::GPR),
_ => unreachable!("can't acquire location for type {:?}", ty),
}; };
let loc = if let Some(x) = loc { let loc = if let Some(x) = loc {

View File

@@ -331,14 +331,6 @@ impl<'data> ModuleEnvironment<'data> {
Ok(()) Ok(())
} }
pub(crate) fn reserve_passive_elements(&mut self, num: u32) -> WasmResult<()> {
self.result
.module
.passive_elements
.reserve_exact(usize::try_from(num).unwrap());
Ok(())
}
pub(crate) fn declare_table_initializers( pub(crate) fn declare_table_initializers(
&mut self, &mut self,
table_index: TableIndex, table_index: TableIndex,
@@ -363,7 +355,16 @@ impl<'data> ModuleEnvironment<'data> {
elem_index: ElemIndex, elem_index: ElemIndex,
segments: Box<[FunctionIndex]>, segments: Box<[FunctionIndex]>,
) -> WasmResult<()> { ) -> WasmResult<()> {
self.result.module.passive_elements[elem_index] = segments; let old = self
.result
.module
.passive_elements
.insert(elem_index, segments);
debug_assert!(
old.is_none(),
"should never get duplicate element indices, that would be a bug in `wasmer_compiler`'s \
translation"
);
Ok(()) Ok(())
} }
@@ -406,7 +407,8 @@ impl<'data> ModuleEnvironment<'data> {
} }
pub(crate) fn reserve_passive_data(&mut self, count: u32) -> WasmResult<()> { pub(crate) fn reserve_passive_data(&mut self, count: u32) -> WasmResult<()> {
self.result.module.passive_data.reserve(count as usize); let count = usize::try_from(count).unwrap();
self.result.module.passive_data.reserve(count);
Ok(()) Ok(())
} }
@@ -415,7 +417,15 @@ impl<'data> ModuleEnvironment<'data> {
data_index: DataIndex, data_index: DataIndex,
data: &'data [u8], data: &'data [u8],
) -> WasmResult<()> { ) -> WasmResult<()> {
self.result.module.passive_data[data_index] = Arc::from(data); let old = self
.result
.module
.passive_data
.insert(data_index, Arc::from(data));
debug_assert!(
old.is_none(),
"a module can't have duplicate indices, this would be a wasmer-compiler bug"
);
Ok(()) Ok(())
} }

View File

@@ -332,7 +332,6 @@ pub fn parse_element_section<'data>(
environ: &mut ModuleEnvironment, environ: &mut ModuleEnvironment,
) -> WasmResult<()> { ) -> WasmResult<()> {
environ.reserve_table_initializers(elements.get_count())?; environ.reserve_table_initializers(elements.get_count())?;
environ.reserve_passive_elements(elements.get_count())?;
for (index, entry) in elements.into_iter().enumerate() { for (index, entry) in elements.into_iter().enumerate() {
let Element { kind, items, ty } = entry?; let Element { kind, items, ty } = entry?;
@@ -372,7 +371,7 @@ pub fn parse_element_section<'data>(
let index = ElemIndex::from_u32(index as u32); let index = ElemIndex::from_u32(index as u32);
environ.declare_passive_element(index, segments)?; environ.declare_passive_element(index, segments)?;
} }
ElementKind::Declared => return Err(wasm_unsupported!("element kind declared")), ElementKind::Declared => (),
} }
} }
Ok(()) Ok(())

View File

@@ -6,7 +6,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
dependencies = [ dependencies = [
"gimli", "gimli 0.22.0",
] ]
[[package]] [[package]]
@@ -134,25 +134,25 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "cranelift-bforest" name = "cranelift-bforest"
version = "0.68.0" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9221545c0507dc08a62b2d8b5ffe8e17ac580b0a74d1813b496b8d70b070fbd0" checksum = "31f782ffb172d8095cbb4c6464d85432c3bcfa8609b0bb1dc27cfd35bd90e052"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
] ]
[[package]] [[package]]
name = "cranelift-codegen" name = "cranelift-codegen"
version = "0.68.0" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9936ea608b6cd176f107037f6adbb4deac933466fc7231154f96598b2d3ab1" checksum = "91e0910022b490bd0a65d5baa1693b0475cdbeea1c26472343f2acea1f1f55b8"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"cranelift-bforest", "cranelift-bforest",
"cranelift-codegen-meta", "cranelift-codegen-meta",
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-entity", "cranelift-entity",
"gimli", "gimli 0.23.0",
"log", "log",
"regalloc", "regalloc",
"smallvec", "smallvec",
@@ -162,9 +162,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.68.0" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ef2b2768568306540f4c8db3acce9105534d34c4a1e440529c1e702d7f8c8d7" checksum = "7cafe95cb5ac659e113549b2794a2c8d3a14f36e1a98728a6e0ea7a773be2129"
dependencies = [ dependencies = [
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-entity", "cranelift-entity",
@@ -172,24 +172,24 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-shared" name = "cranelift-codegen-shared"
version = "0.68.0" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" checksum = "8d1bd002e42cc094a131a8227d06d48df28ea3b9127e5e3bc3010e079858e9af"
[[package]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.68.0" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86badbce14e15f52a45b666b38abe47b204969dd7f8fb7488cb55dd46b361fa6" checksum = "e55e9043403f0dec775f317280015150e78b2352fb947d2f37407fd4ce6311c7"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "cranelift-frontend" name = "cranelift-frontend"
version = "0.68.0" version = "0.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8" checksum = "0153680ebce89aac7cad90a5442bb136faacfc86ea62587a01b8e8e79f8249c9"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"log", "log",
@@ -398,6 +398,12 @@ name = "gimli"
version = "0.22.0" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
[[package]]
name = "gimli"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
dependencies = [ dependencies = [
"fallible-iterator", "fallible-iterator",
"indexmap", "indexmap",
@@ -406,9 +412,9 @@ dependencies = [
[[package]] [[package]]
name = "goblin" name = "goblin"
version = "0.2.3" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" checksum = "669cdc3826f69a51d3f8fc3f86de81c2378110254f678b8407977736122057a4"
dependencies = [ dependencies = [
"log", "log",
"plain", "plain",
@@ -458,9 +464,9 @@ dependencies = [
[[package]] [[package]]
name = "inkwell" name = "inkwell"
version = "0.1.0-llvm10sample" version = "0.1.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e079c12273d96e41481454a37ad968e607e1ce51b39b9facd3a802a12df6e9dc" checksum = "f5fe0be1e47c0c0f3da4397693e08f5d78329ae095c25d529e12ade78420fb41"
dependencies = [ dependencies = [
"either", "either",
"inkwell_internals", "inkwell_internals",
@@ -473,9 +479,9 @@ dependencies = [
[[package]] [[package]]
name = "inkwell_internals" name = "inkwell_internals"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b22cf4eda09069b48204cce4b7cd9a25311da813780e95a038524f2210fab44e" checksum = "c2e1f71330ccec54ee62533ae88574c4169b67fb4b95cbb1196a1322582abd11"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -493,9 +499,9 @@ dependencies = [
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.9.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
dependencies = [ dependencies = [
"either", "either",
] ]
@@ -520,24 +526,25 @@ checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.6.2" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cadb8e769f070c45df05c78c7520eb4cd17061d4ab262e43cfc68b4d00ac71c" checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
dependencies = [ dependencies = [
"cfg-if 1.0.0",
"winapi", "winapi",
] ]
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "100.1.0" version = "110.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5545bf9a09267c644e4d0ac68f37ac200af6579ae2e82aebce382654eb4abab1" checksum = "21ede189444b8c78907e5d36da5dabcf153170fcff9c1dba48afc4b33c7e19f0"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",
"libc", "libc",
"regex", "regex",
"semver 0.9.0", "semver 0.11.0",
] ]
[[package]] [[package]]
@@ -643,9 +650,9 @@ checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
[[package]] [[package]]
name = "object" name = "object"
version = "0.22.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"indexmap", "indexmap",
@@ -653,9 +660,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.4.0" version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
@@ -789,17 +796,6 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "raw-cpuid"
version = "7.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf"
dependencies = [
"bitflags",
"cc",
"rustc_version",
]
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.5.0" version = "1.5.0"
@@ -1148,7 +1144,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasmer" name = "wasmer"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"indexmap", "indexmap",
@@ -1171,7 +1167,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-cache" name = "wasmer-cache"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"blake3", "blake3",
"hex", "hex",
@@ -1181,10 +1177,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler" name = "wasmer-compiler"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"enumset", "enumset",
"raw-cpuid",
"serde", "serde",
"serde_bytes", "serde_bytes",
"smallvec", "smallvec",
@@ -1197,11 +1192,11 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-cranelift" name = "wasmer-compiler-cranelift"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-frontend", "cranelift-frontend",
"gimli", "gimli 0.23.0",
"more-asserts", "more-asserts",
"rayon", "rayon",
"serde", "serde",
@@ -1214,7 +1209,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-llvm" name = "wasmer-compiler-llvm"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"cc", "cc",
@@ -1236,7 +1231,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-singlepass" name = "wasmer-compiler-singlepass"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"dynasm", "dynasm",
@@ -1253,7 +1248,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-derive" name = "wasmer-derive"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@@ -1263,7 +1258,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine" name = "wasmer-engine"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bincode", "bincode",
@@ -1282,7 +1277,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-jit" name = "wasmer-engine-jit"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@@ -1298,7 +1293,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-native" name = "wasmer-engine-native"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@@ -1317,9 +1312,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-object" name = "wasmer-object"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"object 0.22.0", "object 0.23.0",
"thiserror", "thiserror",
"wasmer-compiler", "wasmer-compiler",
"wasmer-types", "wasmer-types",
@@ -1345,7 +1340,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-types" name = "wasmer-types"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
"serde", "serde",
@@ -1354,7 +1349,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-vm" name = "wasmer-vm"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"cc", "cc",
@@ -1372,9 +1367,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.65.0" version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" checksum = "4a4d63608421d9a22d4bce220f2841f3b609a5aaabd3ed3aeeb5fed2702c3c78"
[[package]] [[package]]
name = "wast" name = "wast"

View File

@@ -100,7 +100,7 @@ mod table_tests {
minimum: 10, minimum: 10,
maximum: Some(20), maximum: Some(20),
}, },
Value::null(), Value::FuncRef(None),
) )
.unwrap(); .unwrap();
assert_eq!(table.size(), 10); assert_eq!(table.size(), 10);

View File

@@ -150,10 +150,11 @@ pub fn _gai_strerror(ctx: &EmEnv, ecode: i32) -> i32 {
let cstr = unsafe { std::ffi::CStr::from_ptr(libc::gai_strerror(ecode)) }; let cstr = unsafe { std::ffi::CStr::from_ptr(libc::gai_strerror(ecode)) };
let bytes = cstr.to_bytes_with_nul(); let bytes = cstr.to_bytes_with_nul();
let string_on_guest: WasmPtr<c_char, Array> = call_malloc_with_cast(ctx, bytes.len() as _); let string_on_guest: WasmPtr<c_char, Array> = call_malloc_with_cast(ctx, bytes.len() as _);
let memory = ctx.memory(0);
let writer = unsafe { let writer = unsafe {
string_on_guest string_on_guest
.deref_mut(ctx.memory(0), 0, bytes.len() as _) .deref_mut(&memory, 0, bytes.len() as _)
.unwrap() .unwrap()
}; };
for (i, byte) in bytes.iter().enumerate() { for (i, byte) in bytes.iter().enumerate() {
@@ -175,7 +176,7 @@ pub fn _getaddrinfo(
let memory = ctx.memory(0); let memory = ctx.memory(0);
debug!(" => node = {}", unsafe { debug!(" => node = {}", unsafe {
node_ptr node_ptr
.deref(memory) .deref(&memory)
.map(|np| { .map(|np| {
std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char) std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
.to_string_lossy() .to_string_lossy()
@@ -184,7 +185,7 @@ pub fn _getaddrinfo(
}); });
debug!(" => server_str = {}", unsafe { debug!(" => server_str = {}", unsafe {
service_str_ptr service_str_ptr
.deref(memory) .deref(&memory)
.map(|np| { .map(|np| {
std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char) std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
.to_string_lossy() .to_string_lossy()
@@ -192,7 +193,7 @@ pub fn _getaddrinfo(
.unwrap_or(std::borrow::Cow::Borrowed("null")) .unwrap_or(std::borrow::Cow::Borrowed("null"))
}); });
let hints = hints_ptr.deref(memory).map(|hints_memory| { let hints = hints_ptr.deref(&memory).map(|hints_memory| {
let hints_guest = hints_memory.get(); let hints_guest = hints_memory.get();
addrinfo { addrinfo {
ai_flags: hints_guest.ai_flags, ai_flags: hints_guest.ai_flags,
@@ -212,11 +213,11 @@ pub fn _getaddrinfo(
let result = unsafe { let result = unsafe {
libc::getaddrinfo( libc::getaddrinfo(
(node_ptr (node_ptr
.deref(memory) .deref(&memory)
.map(|m| m as *const Cell<c_char> as *const c_char)) .map(|m| m as *const Cell<c_char> as *const c_char))
.unwrap_or(std::ptr::null()), .unwrap_or(std::ptr::null()),
service_str_ptr service_str_ptr
.deref(memory) .deref(&memory)
.map(|m| m as *const Cell<c_char> as *const c_char) .map(|m| m as *const Cell<c_char> as *const c_char)
.unwrap_or(std::ptr::null()), .unwrap_or(std::ptr::null()),
hints hints
@@ -245,7 +246,7 @@ pub fn _getaddrinfo(
// connect list // connect list
if let Some(prev_guest) = previous_guest_node { if let Some(prev_guest) = previous_guest_node {
let mut pg = prev_guest.deref_mut(ctx.memory(0)).unwrap().get_mut(); let mut pg = prev_guest.deref_mut(&memory).unwrap().get_mut();
pg.ai_next = current_guest_node_ptr; pg.ai_next = current_guest_node_ptr;
} }
@@ -257,10 +258,7 @@ pub fn _getaddrinfo(
let host_sockaddr_ptr = (*current_host_node).ai_addr; let host_sockaddr_ptr = (*current_host_node).ai_addr;
let guest_sockaddr_ptr: WasmPtr<EmSockAddr> = let guest_sockaddr_ptr: WasmPtr<EmSockAddr> =
call_malloc_with_cast(ctx, host_addrlen as _); call_malloc_with_cast(ctx, host_addrlen as _);
let guest_sockaddr = guest_sockaddr_ptr let guest_sockaddr = guest_sockaddr_ptr.deref_mut(&memory).unwrap().get_mut();
.deref_mut(ctx.memory(0))
.unwrap()
.get_mut();
guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16; guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16;
guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data; guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data;
@@ -277,9 +275,8 @@ pub fn _getaddrinfo(
let guest_canonname: WasmPtr<c_char, Array> = let guest_canonname: WasmPtr<c_char, Array> =
call_malloc_with_cast(ctx, str_size as _); call_malloc_with_cast(ctx, str_size as _);
let guest_canonname_writer = guest_canonname let guest_canonname_writer =
.deref(ctx.memory(0), 0, str_size as _) guest_canonname.deref(&memory, 0, str_size as _).unwrap();
.unwrap();
for (i, b) in canonname_bytes.into_iter().enumerate() { for (i, b) in canonname_bytes.into_iter().enumerate() {
guest_canonname_writer[i].set(*b as _) guest_canonname_writer[i].set(*b as _)
} }
@@ -290,10 +287,8 @@ pub fn _getaddrinfo(
} }
}; };
let mut current_guest_node = current_guest_node_ptr let mut current_guest_node =
.deref_mut(ctx.memory(0)) current_guest_node_ptr.deref_mut(&memory).unwrap().get_mut();
.unwrap()
.get_mut();
current_guest_node.ai_flags = (*current_host_node).ai_flags; current_guest_node.ai_flags = (*current_host_node).ai_flags;
current_guest_node.ai_family = (*current_host_node).ai_family; current_guest_node.ai_family = (*current_host_node).ai_family;
current_guest_node.ai_socktype = (*current_host_node).ai_socktype; current_guest_node.ai_socktype = (*current_host_node).ai_socktype;
@@ -311,7 +306,7 @@ pub fn _getaddrinfo(
head_of_list.unwrap_or_else(|| WasmPtr::new(0)) head_of_list.unwrap_or_else(|| WasmPtr::new(0))
}; };
res_val_ptr.deref(ctx.memory(0)).unwrap().set(head_of_list); res_val_ptr.deref(&memory).unwrap().set(head_of_list);
0 0
} }

View File

@@ -19,7 +19,8 @@ extern "C" {
/// emscripten: _getenv // (name: *const char) -> *const c_char; /// emscripten: _getenv // (name: *const char) -> *const c_char;
pub fn _getenv(ctx: &EmEnv, name: u32) -> u32 { pub fn _getenv(ctx: &EmEnv, name: u32) -> u32 {
debug!("emscripten::_getenv"); debug!("emscripten::_getenv");
let name_string = read_string_from_wasm(ctx.memory(0), name); let memory = ctx.memory(0);
let name_string = read_string_from_wasm(&memory, name);
debug!("=> name({:?})", name_string); debug!("=> name({:?})", name_string);
let c_str = unsafe { getenv(name_string.as_ptr() as *const libc::c_char) }; let c_str = unsafe { getenv(name_string.as_ptr() as *const libc::c_char) };
if c_str.is_null() { if c_str.is_null() {
@@ -31,9 +32,10 @@ pub fn _getenv(ctx: &EmEnv, name: u32) -> u32 {
/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int); /// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int);
pub fn _setenv(ctx: &EmEnv, name: u32, value: u32, _overwrite: u32) -> c_int { pub fn _setenv(ctx: &EmEnv, name: u32, value: u32, _overwrite: u32) -> c_int {
debug!("emscripten::_setenv"); debug!("emscripten::_setenv");
let memory = ctx.memory(0);
// setenv does not exist on windows, so we hack it with _putenv // setenv does not exist on windows, so we hack it with _putenv
let name = read_string_from_wasm(ctx.memory(0), name); let name = read_string_from_wasm(&memory, name);
let value = read_string_from_wasm(ctx.memory(0), value); let value = read_string_from_wasm(&memory, value);
let putenv_string = format!("{}={}", name, value); let putenv_string = format!("{}={}", name, value);
let putenv_cstring = CString::new(putenv_string).unwrap(); let putenv_cstring = CString::new(putenv_string).unwrap();
let putenv_raw_ptr = putenv_cstring.as_ptr(); let putenv_raw_ptr = putenv_cstring.as_ptr();
@@ -45,7 +47,8 @@ pub fn _setenv(ctx: &EmEnv, name: u32, value: u32, _overwrite: u32) -> c_int {
/// emscripten: _putenv // (name: *const char); /// emscripten: _putenv // (name: *const char);
pub fn _putenv(ctx: &EmEnv, name: c_int) -> c_int { pub fn _putenv(ctx: &EmEnv, name: c_int) -> c_int {
debug!("emscripten::_putenv"); debug!("emscripten::_putenv");
let name_addr = emscripten_memory_pointer!(ctx.memory(0), name) as *const c_char; let memory = ctx.memory(0);
let name_addr = emscripten_memory_pointer!(&memory, name) as *const c_char;
debug!("=> name({:?})", unsafe { debug!("=> name({:?})", unsafe {
std::ffi::CStr::from_ptr(name_addr) std::ffi::CStr::from_ptr(name_addr)
}); });
@@ -55,7 +58,8 @@ pub fn _putenv(ctx: &EmEnv, name: c_int) -> c_int {
/// emscripten: _unsetenv // (name: *const char); /// emscripten: _unsetenv // (name: *const char);
pub fn _unsetenv(ctx: &EmEnv, name: u32) -> c_int { pub fn _unsetenv(ctx: &EmEnv, name: u32) -> c_int {
debug!("emscripten::_unsetenv"); debug!("emscripten::_unsetenv");
let name = read_string_from_wasm(ctx.memory(0), name); let memory = ctx.memory(0);
let name = read_string_from_wasm(&memory, name);
// no unsetenv on windows, so use putenv with an empty value // no unsetenv on windows, so use putenv with an empty value
let unsetenv_string = format!("{}=", name); let unsetenv_string = format!("{}=", name);
let unsetenv_cstring = CString::new(unsetenv_string).unwrap(); let unsetenv_cstring = CString::new(unsetenv_string).unwrap();
@@ -69,6 +73,7 @@ pub fn _getpwnam(ctx: &EmEnv, name_ptr: c_int) -> c_int {
debug!("emscripten::_getpwnam {}", name_ptr); debug!("emscripten::_getpwnam {}", name_ptr);
#[cfg(not(feature = "debug"))] #[cfg(not(feature = "debug"))]
let _ = name_ptr; let _ = name_ptr;
let memory = ctx.memory(0);
#[repr(C)] #[repr(C)]
struct GuestPasswd { struct GuestPasswd {
@@ -85,7 +90,7 @@ pub fn _getpwnam(ctx: &EmEnv, name_ptr: c_int) -> c_int {
unsafe { unsafe {
let passwd_struct_offset = call_malloc(ctx, mem::size_of::<GuestPasswd>() as _); let passwd_struct_offset = call_malloc(ctx, mem::size_of::<GuestPasswd>() as _);
let passwd_struct_ptr = let passwd_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), passwd_struct_offset) as *mut GuestPasswd; emscripten_memory_pointer!(&memory, passwd_struct_offset) as *mut GuestPasswd;
(*passwd_struct_ptr).pw_name = 0; (*passwd_struct_ptr).pw_name = 0;
(*passwd_struct_ptr).pw_passwd = 0; (*passwd_struct_ptr).pw_passwd = 0;
(*passwd_struct_ptr).pw_gecos = 0; (*passwd_struct_ptr).pw_gecos = 0;
@@ -103,6 +108,7 @@ pub fn _getgrnam(ctx: &EmEnv, name_ptr: c_int) -> c_int {
debug!("emscripten::_getgrnam {}", name_ptr); debug!("emscripten::_getgrnam {}", name_ptr);
#[cfg(not(feature = "debug"))] #[cfg(not(feature = "debug"))]
let _ = name_ptr; let _ = name_ptr;
let memory = ctx.memory(0);
#[repr(C)] #[repr(C)]
struct GuestGroup { struct GuestGroup {
@@ -116,7 +122,7 @@ pub fn _getgrnam(ctx: &EmEnv, name_ptr: c_int) -> c_int {
unsafe { unsafe {
let group_struct_offset = call_malloc(ctx, mem::size_of::<GuestGroup>() as _); let group_struct_offset = call_malloc(ctx, mem::size_of::<GuestGroup>() as _);
let group_struct_ptr = let group_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), group_struct_offset) as *mut GuestGroup; emscripten_memory_pointer!(&memory, group_struct_offset) as *mut GuestGroup;
(*group_struct_ptr).gr_name = 0; (*group_struct_ptr).gr_name = 0;
(*group_struct_ptr).gr_passwd = 0; (*group_struct_ptr).gr_passwd = 0;
(*group_struct_ptr).gr_gid = 0; (*group_struct_ptr).gr_gid = 0;

View File

@@ -17,11 +17,11 @@ use lazy_static::lazy_static;
use std::collections::HashMap; use std::collections::HashMap;
use std::f64; use std::f64;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, RwLock};
use wasmer::{ use wasmer::{
imports, namespace, Exports, ExternRef, Function, FunctionType, Global, ImportObject, Instance, imports, namespace, Exports, Function, FunctionType, Global, ImportObject, Instance, LazyInit,
LazyInit, Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, Val,
Val, ValType, WasmerEnv, ValType, WasmerEnv,
}; };
#[cfg(unix)] #[cfg(unix)]
@@ -71,7 +71,7 @@ pub use self::utils::{
#[derive(Clone)] #[derive(Clone)]
/// The environment provided to the Emscripten imports. /// The environment provided to the Emscripten imports.
pub struct EmEnv { pub struct EmEnv {
memory: Arc<Option<Memory>>, memory: Arc<RwLock<Option<Memory>>>,
data: Arc<Mutex<EmscriptenData>>, data: Arc<Mutex<EmscriptenData>>,
} }
@@ -86,21 +86,19 @@ impl WasmerEnv for EmEnv {
impl EmEnv { impl EmEnv {
pub fn new(data: &EmscriptenGlobalsData, mapped_dirs: HashMap<String, PathBuf>) -> Self { pub fn new(data: &EmscriptenGlobalsData, mapped_dirs: HashMap<String, PathBuf>) -> Self {
Self { Self {
memory: Arc::new(None), memory: Arc::new(RwLock::new(None)),
data: Arc::new(Mutex::new(EmscriptenData::new(data.clone(), mapped_dirs))), data: Arc::new(Mutex::new(EmscriptenData::new(data.clone(), mapped_dirs))),
} }
} }
pub fn set_memory(&mut self, memory: Memory) { pub fn set_memory(&mut self, memory: Memory) {
let ptr = Arc::as_ptr(&self.memory) as *mut _; let mut w = self.memory.write().unwrap();
unsafe { *w = Some(memory);
*ptr = Some(memory);
}
} }
/// Get a reference to the memory /// Get a reference to the memory
pub fn memory(&self, _mem_idx: u32) -> &Memory { pub fn memory(&self, _mem_idx: u32) -> Memory {
(*self.memory).as_ref().unwrap() (&*self.memory.read().unwrap()).as_ref().cloned().unwrap()
} }
} }
@@ -324,10 +322,10 @@ pub fn emscripten_call_main(
) -> Result<(), RuntimeError> { ) -> Result<(), RuntimeError> {
let (function_name, main_func) = match instance.exports.get::<Function>("_main") { let (function_name, main_func) = match instance.exports.get::<Function>("_main") {
Ok(func) => Ok(("_main", func)), Ok(func) => Ok(("_main", func)),
Err(_e) => match instance.exports.get::<Function>("main") { Err(_e) => instance
Ok(func) => Ok(("main", func)), .exports
Err(e) => Err(e), .get::<Function>("main")
}, .map(|func| ("main", func)),
} }
.map_err(|e| RuntimeError::new(e.to_string()))?; .map_err(|e| RuntimeError::new(e.to_string()))?;
let num_params = main_func.ty().params().len(); let num_params = main_func.ty().params().len();
@@ -477,8 +475,7 @@ impl EmscriptenGlobals {
minimum: table_min, minimum: table_min,
maximum: table_max, maximum: table_max,
}; };
// TODO: review init value let table = Table::new(store, table_type, Val::FuncRef(None)).unwrap();
let table = Table::new(store, table_type, Val::ExternRef(ExternRef::null())).unwrap();
let data = { let data = {
let static_bump = STATIC_BUMP; let static_bump = STATIC_BUMP;

View File

@@ -356,8 +356,9 @@ pub fn ___syscall183(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> i32 {
let path = get_current_directory(ctx); let path = get_current_directory(ctx);
let path_string = path.unwrap().display().to_string(); let path_string = path.unwrap().display().to_string();
let len = path_string.len(); let len = path_string.len();
let memory = ctx.memory(0);
let buf_writer = buf_offset.deref(ctx.memory(0), 0, len as u32 + 1).unwrap(); let buf_writer = buf_offset.deref(&memory, 0, len as u32 + 1).unwrap();
for (i, byte) in path_string.bytes().enumerate() { for (i, byte) in path_string.bytes().enumerate() {
buf_writer[i].set(byte as _); buf_writer[i].set(byte as _);
} }
@@ -411,8 +412,9 @@ pub fn ___syscall140(ctx: &EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
let whence: i32 = varargs.get(ctx); let whence: i32 = varargs.get(ctx);
let offset = offset_low; let offset = offset_low;
let ret = unsafe { lseek(fd, offset as _, whence) as i64 }; let ret = unsafe { lseek(fd, offset as _, whence) as i64 };
let memory = ctx.memory(0);
let result_ptr = result_ptr_value.deref(ctx.memory(0)).unwrap(); let result_ptr = result_ptr_value.deref(&memory).unwrap();
result_ptr.set(ret); result_ptr.set(ret);
debug!( debug!(

View File

@@ -515,6 +515,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
debug!("emscripten::___syscall102 (socketcall) {}", _which); debug!("emscripten::___syscall102 (socketcall) {}", _which);
let call: u32 = varargs.get(ctx); let call: u32 = varargs.get(ctx);
let mut socket_varargs: VarArgs = varargs.get(ctx); let mut socket_varargs: VarArgs = varargs.get(ctx);
let memory = ctx.memory(0);
// migrating to EmSockAddr, port being separate here is nice, should update that too // migrating to EmSockAddr, port being separate here is nice, should update that too
#[repr(C)] #[repr(C)]
@@ -579,7 +580,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket = socket_varargs.get(ctx); let socket = socket_varargs.get(ctx);
let address: u32 = socket_varargs.get(ctx); let address: u32 = socket_varargs.get(ctx);
let address_len = socket_varargs.get(ctx); let address_len = socket_varargs.get(ctx);
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address = emscripten_memory_pointer!(&memory, address) as *mut sockaddr;
// Debug received address // Debug received address
let _proper_address = address as *const GuestSockaddrIn; let _proper_address = address as *const GuestSockaddrIn;
@@ -604,7 +605,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket = socket_varargs.get(ctx); let socket = socket_varargs.get(ctx);
let address: u32 = socket_varargs.get(ctx); let address: u32 = socket_varargs.get(ctx);
let address_len = socket_varargs.get(ctx); let address_len = socket_varargs.get(ctx);
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address = emscripten_memory_pointer!(&memory, address) as *mut sockaddr;
unsafe { connect(socket, address, address_len) } unsafe { connect(socket, address, address_len) }
} }
4 => { 4 => {
@@ -629,11 +630,10 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
debug!( debug!(
"=> socket: {}, address: {:?}, address_len: {}", "=> socket: {}, address: {:?}, address_len: {}",
socket, socket,
address.deref(ctx.memory(0)).unwrap().get(), address.deref(&memory).unwrap().get(),
address_len.deref(ctx.memory(0)).unwrap().get() address_len.deref(&memory).unwrap().get()
); );
let address_len_addr = let address_len_addr = unsafe { address_len.deref_mut(&memory).unwrap().get_mut() };
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
// let mut address_len_addr: socklen_t = 0; // let mut address_len_addr: socklen_t = 0;
let mut host_address: sockaddr = sockaddr { let mut host_address: sockaddr = sockaddr {
@@ -643,7 +643,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
sa_len: Default::default(), sa_len: Default::default(),
}; };
let fd = unsafe { accept(socket, &mut host_address, address_len_addr) }; let fd = unsafe { accept(socket, &mut host_address, address_len_addr) };
let address_addr = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() }; let address_addr = unsafe { address.deref_mut(&memory).unwrap().get_mut() };
address_addr.sa_family = host_address.sa_family as _; address_addr.sa_family = host_address.sa_family as _;
address_addr.sa_data = host_address.sa_data; address_addr.sa_data = host_address.sa_data;
@@ -667,8 +667,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket: i32 = socket_varargs.get(ctx); let socket: i32 = socket_varargs.get(ctx);
let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx); let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx);
let address_len: WasmPtr<u32> = socket_varargs.get(ctx); let address_len: WasmPtr<u32> = socket_varargs.get(ctx);
let address_len_addr = let address_len_addr = unsafe { address_len.deref_mut(&memory).unwrap().get_mut() };
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
let mut sock_addr_host: sockaddr = sockaddr { let mut sock_addr_host: sockaddr = sockaddr {
sa_family: Default::default(), sa_family: Default::default(),
@@ -684,7 +683,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
) )
}; };
// translate from host data into emscripten data // translate from host data into emscripten data
let mut address_mut = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() }; let mut address_mut = unsafe { address.deref_mut(&memory).unwrap().get_mut() };
address_mut.sa_family = sock_addr_host.sa_family as _; address_mut.sa_family = sock_addr_host.sa_family as _;
address_mut.sa_data = sock_addr_host.sa_data; address_mut.sa_data = sock_addr_host.sa_data;
@@ -701,9 +700,9 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket = socket_varargs.get(ctx); let socket = socket_varargs.get(ctx);
let address: u32 = socket_varargs.get(ctx); let address: u32 = socket_varargs.get(ctx);
let address_len: u32 = socket_varargs.get(ctx); let address_len: u32 = socket_varargs.get(ctx);
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address = emscripten_memory_pointer!(memory, address) as *mut sockaddr;
let address_len_addr = let address_len_addr =
emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; emscripten_memory_pointer!(memory, address_len) as *mut socklen_t;
unsafe { getpeername(socket, address, address_len_addr) } unsafe { getpeername(socket, address, address_len_addr) }
} }
11 => { 11 => {
@@ -715,8 +714,8 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let len: i32 = socket_varargs.get(ctx); let len: i32 = socket_varargs.get(ctx);
let address: u32 = socket_varargs.get(ctx); let address: u32 = socket_varargs.get(ctx);
let address_len = socket_varargs.get(ctx); let address_len = socket_varargs.get(ctx);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as _; let buf_addr = emscripten_memory_pointer!(memory, buf) as _;
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address = emscripten_memory_pointer!(memory, address) as *mut sockaddr;
unsafe { sendto(socket, buf_addr, flags, len, address, address_len) as i32 } unsafe { sendto(socket, buf_addr, flags, len, address, address_len) as i32 }
} }
12 => { 12 => {
@@ -728,10 +727,10 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let flags: i32 = socket_varargs.get(ctx); let flags: i32 = socket_varargs.get(ctx);
let address: u32 = socket_varargs.get(ctx); let address: u32 = socket_varargs.get(ctx);
let address_len: u32 = socket_varargs.get(ctx); let address_len: u32 = socket_varargs.get(ctx);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as _; let buf_addr = emscripten_memory_pointer!(memory, buf) as _;
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; let address = emscripten_memory_pointer!(memory, address) as *mut sockaddr;
let address_len_addr = let address_len_addr =
emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; emscripten_memory_pointer!(memory, address_len) as *mut socklen_t;
unsafe { unsafe {
recvfrom( recvfrom(
socket, socket,
@@ -755,8 +754,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let untranslated_name: i32 = socket_varargs.get(ctx); let untranslated_name: i32 = socket_varargs.get(ctx);
let value: u32 = socket_varargs.get(ctx); let value: u32 = socket_varargs.get(ctx);
let option_len: u32 = socket_varargs.get(ctx); let option_len: u32 = socket_varargs.get(ctx);
let value_addr = let value_addr = emscripten_memory_pointer!(memory, value) as *const libc::c_void;
emscripten_memory_pointer!(ctx.memory(0), value) as *const libc::c_void;
let name: i32 = translate_socket_name_flag(untranslated_name); let name: i32 = translate_socket_name_flag(untranslated_name);
let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) }; let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) };
@@ -774,9 +772,8 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let name: i32 = translate_socket_name_flag(untranslated_name); let name: i32 = translate_socket_name_flag(untranslated_name);
let value: u32 = socket_varargs.get(ctx); let value: u32 = socket_varargs.get(ctx);
let option_len: u32 = socket_varargs.get(ctx); let option_len: u32 = socket_varargs.get(ctx);
let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; let value_addr = emscripten_memory_pointer!(memory, value) as _;
let option_len_addr = let option_len_addr = emscripten_memory_pointer!(memory, option_len) as *mut socklen_t;
emscripten_memory_pointer!(ctx.memory(0), option_len) as *mut socklen_t;
unsafe { getsockopt(socket, level, name, value_addr, option_len_addr) } unsafe { getsockopt(socket, level, name, value_addr, option_len_addr) }
} }
16 => { 16 => {
@@ -785,7 +782,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket: i32 = socket_varargs.get(ctx); let socket: i32 = socket_varargs.get(ctx);
let msg: u32 = socket_varargs.get(ctx); let msg: u32 = socket_varargs.get(ctx);
let flags: i32 = socket_varargs.get(ctx); let flags: i32 = socket_varargs.get(ctx);
let msg_addr = emscripten_memory_pointer!(ctx.memory(0), msg) as *const msghdr; let msg_addr = emscripten_memory_pointer!(memory, msg) as *const msghdr;
unsafe { sendmsg(socket, msg_addr, flags) as i32 } unsafe { sendmsg(socket, msg_addr, flags) as i32 }
} }
17 => { 17 => {
@@ -794,7 +791,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket: i32 = socket_varargs.get(ctx); let socket: i32 = socket_varargs.get(ctx);
let msg: u32 = socket_varargs.get(ctx); let msg: u32 = socket_varargs.get(ctx);
let flags: i32 = socket_varargs.get(ctx); let flags: i32 = socket_varargs.get(ctx);
let msg_addr = emscripten_memory_pointer!(ctx.memory(0), msg) as *mut msghdr; let msg_addr = emscripten_memory_pointer!(memory, msg) as *mut msghdr;
unsafe { recvmsg(socket, msg_addr, flags) as i32 } unsafe { recvmsg(socket, msg_addr, flags) as i32 }
} }
_ => { _ => {
@@ -858,8 +855,9 @@ pub fn ___syscall168(ctx: &EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
let fds: WasmPtr<EmPollFd> = varargs.get(ctx); let fds: WasmPtr<EmPollFd> = varargs.get(ctx);
let nfds: u32 = varargs.get(ctx); let nfds: u32 = varargs.get(ctx);
let timeout: i32 = varargs.get(ctx); let timeout: i32 = varargs.get(ctx);
let memory = ctx.memory(0);
let fds_mut = unsafe { fds.deref_mut(ctx.memory(0)).unwrap().get_mut() }; let fds_mut = unsafe { fds.deref_mut(&memory).unwrap().get_mut() };
let ret = unsafe { let ret = unsafe {
libc::poll( libc::poll(

View File

@@ -27,6 +27,8 @@ pub fn ___syscall5(ctx: &EmEnv, which: c_int, mut varargs: VarArgs) -> c_int {
let flags: i32 = varargs.get(ctx); let flags: i32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx);
let path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }; let path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() };
let memory = ctx.memory(0);
match path_str { match path_str {
"/dev/urandom" => { "/dev/urandom" => {
// create a fake urandom file for windows, super hacky // create a fake urandom file for windows, super hacky
@@ -44,7 +46,7 @@ pub fn ___syscall5(ctx: &EmEnv, which: c_int, mut varargs: VarArgs) -> c_int {
// put the file path string into wasm memory // put the file path string into wasm memory
let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) }; let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) };
let raw_pointer_to_urandom_file = let raw_pointer_to_urandom_file =
emscripten_memory_pointer!(ctx.memory(0), urandom_file_offset) as *const i8; emscripten_memory_pointer!(&memory, urandom_file_offset) as *const i8;
let fd = unsafe { open(raw_pointer_to_urandom_file, flags, mode) }; let fd = unsafe { open(raw_pointer_to_urandom_file, flags, mode) };
debug!( debug!(
"=> pathname: {}, flags: {}, mode: {} = fd: {}", "=> pathname: {}, flags: {}, mode: {} = fd: {}",

View File

@@ -23,7 +23,8 @@ use wasmer_types::{
TableIndex, TableIndex,
}; };
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex, VMTrampoline, FuncDataRegistry, FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex,
VMTrampoline,
}; };
/// A compiled wasm module, ready to be instantiated. /// A compiled wasm module, ready to be instantiated.
@@ -35,6 +36,7 @@ pub struct JITArtifact {
finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>, finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>, finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>, signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
func_data_registry: Arc<FuncDataRegistry>,
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>, frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>, finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
} }
@@ -226,6 +228,7 @@ impl JITArtifact {
let finished_dynamic_function_trampolines = let finished_dynamic_function_trampolines =
finished_dynamic_function_trampolines.into_boxed_slice(); finished_dynamic_function_trampolines.into_boxed_slice();
let signatures = signatures.into_boxed_slice(); let signatures = signatures.into_boxed_slice();
let func_data_registry = inner_jit.func_data().clone();
Ok(Self { Ok(Self {
serializable, serializable,
@@ -235,6 +238,7 @@ impl JITArtifact {
signatures, signatures,
frame_info_registration: Mutex::new(None), frame_info_registration: Mutex::new(None),
finished_function_lengths, finished_function_lengths,
func_data_registry,
}) })
} }
@@ -314,6 +318,9 @@ impl Artifact for JITArtifact {
&self.signatures &self.signatures
} }
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn serialize(&self) -> Result<Vec<u8>, SerializeError> { fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
// let mut s = flexbuffers::FlexbufferSerializer::new(); // let mut s = flexbuffers::FlexbufferSerializer::new();
// self.serializable.serialize(&mut s).map_err(|e| SerializeError::Generic(format!("{:?}", e))); // self.serializable.serialize(&mut s).map_err(|e| SerializeError::Generic(format!("{:?}", e)));

View File

@@ -13,8 +13,8 @@ use wasmer_types::entity::PrimaryMap;
use wasmer_types::Features; use wasmer_types::Features;
use wasmer_types::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex}; use wasmer_types::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex};
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, ModuleInfo, SectionBodyPtr, SignatureRegistry, VMFunctionBody, FuncDataRegistry, FunctionBodyPtr, ModuleInfo, SectionBodyPtr, SignatureRegistry,
VMSharedSignatureIndex, VMTrampoline, VMCallerCheckedAnyfunc, VMFuncRef, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
}; };
/// A WebAssembly `JIT` Engine. /// A WebAssembly `JIT` Engine.
@@ -35,6 +35,7 @@ impl JITEngine {
compiler: Some(compiler), compiler: Some(compiler),
code_memory: vec![], code_memory: vec![],
signatures: SignatureRegistry::new(), signatures: SignatureRegistry::new(),
func_data: Arc::new(FuncDataRegistry::new()),
features, features,
})), })),
target: Arc::new(target), target: Arc::new(target),
@@ -62,6 +63,7 @@ impl JITEngine {
compiler: None, compiler: None,
code_memory: vec![], code_memory: vec![],
signatures: SignatureRegistry::new(), signatures: SignatureRegistry::new(),
func_data: Arc::new(FuncDataRegistry::new()),
features: Features::default(), features: Features::default(),
})), })),
target: Arc::new(Target::default()), target: Arc::new(Target::default()),
@@ -90,6 +92,11 @@ impl Engine for JITEngine {
compiler.signatures().register(func_type) compiler.signatures().register(func_type)
} }
fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
let compiler = self.inner();
compiler.func_data().register(func_data)
}
/// Lookup a signature /// Lookup a signature
fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> { fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
let compiler = self.inner(); let compiler = self.inner();
@@ -152,6 +159,10 @@ pub struct JITEngineInner {
/// The signature registry is used mainly to operate with trampolines /// The signature registry is used mainly to operate with trampolines
/// performantly. /// performantly.
signatures: SignatureRegistry, signatures: SignatureRegistry,
/// The backing storage of `VMFuncRef`s. This centralized store ensures that 2
/// functions with the same `VMCallerCheckedAnyfunc` will have the same `VMFuncRef`.
/// It also guarantees that the `VMFuncRef`s stay valid until the engine is dropped.
func_data: Arc<FuncDataRegistry>,
} }
impl JITEngineInner { impl JITEngineInner {
@@ -299,4 +310,9 @@ impl JITEngineInner {
pub fn signatures(&self) -> &SignatureRegistry { pub fn signatures(&self) -> &SignatureRegistry {
&self.signatures &self.signatures
} }
/// Shared func metadata registry.
pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
&self.func_data
}
} }

View File

@@ -33,8 +33,8 @@ use wasmer_types::{
TableIndex, TableIndex,
}; };
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody, VMSharedSignatureIndex, FuncDataRegistry, FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody,
VMTrampoline, VMSharedSignatureIndex, VMTrampoline,
}; };
/// A compiled wasm module, ready to be instantiated. /// A compiled wasm module, ready to be instantiated.
@@ -46,6 +46,7 @@ pub struct NativeArtifact {
#[loupe(skip)] #[loupe(skip)]
finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>, finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>, finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
func_data_registry: Arc<FuncDataRegistry>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>, signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
} }
@@ -356,6 +357,7 @@ impl NativeArtifact {
.into_boxed_slice(), .into_boxed_slice(),
finished_dynamic_function_trampolines: finished_dynamic_function_trampolines finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
.into_boxed_slice(), .into_boxed_slice(),
func_data_registry: Arc::new(FuncDataRegistry::new()),
signatures: signatures.into_boxed_slice(), signatures: signatures.into_boxed_slice(),
}) })
} }
@@ -459,6 +461,7 @@ impl NativeArtifact {
.into_boxed_slice(), .into_boxed_slice(),
finished_dynamic_function_trampolines: finished_dynamic_function_trampolines finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
.into_boxed_slice(), .into_boxed_slice(),
func_data_registry: engine_inner.func_data().clone(),
signatures: signatures.into_boxed_slice(), signatures: signatures.into_boxed_slice(),
}) })
} }
@@ -613,6 +616,10 @@ impl Artifact for NativeArtifact {
&self.signatures &self.signatures
} }
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn preinstantiate(&self) -> Result<(), InstantiationError> { fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(()) Ok(())
} }

View File

@@ -13,7 +13,9 @@ use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use wasmer_types::Features; use wasmer_types::Features;
use wasmer_types::FunctionType; use wasmer_types::FunctionType;
use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex}; use wasmer_vm::{
FuncDataRegistry, SignatureRegistry, VMCallerCheckedAnyfunc, VMFuncRef, VMSharedSignatureIndex,
};
/// A WebAssembly `Native` Engine. /// A WebAssembly `Native` Engine.
#[derive(Clone, MemoryUsage)] #[derive(Clone, MemoryUsage)]
@@ -35,6 +37,7 @@ impl NativeEngine {
inner: Arc::new(Mutex::new(NativeEngineInner { inner: Arc::new(Mutex::new(NativeEngineInner {
compiler: Some(compiler), compiler: Some(compiler),
signatures: SignatureRegistry::new(), signatures: SignatureRegistry::new(),
func_data: Arc::new(FuncDataRegistry::new()),
prefixer: None, prefixer: None,
features, features,
is_cross_compiling, is_cross_compiling,
@@ -67,6 +70,7 @@ impl NativeEngine {
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
features: Features::default(), features: Features::default(),
signatures: SignatureRegistry::new(), signatures: SignatureRegistry::new(),
func_data: Arc::new(FuncDataRegistry::new()),
prefixer: None, prefixer: None,
is_cross_compiling: false, is_cross_compiling: false,
linker: Linker::None, linker: Linker::None,
@@ -116,6 +120,11 @@ impl Engine for NativeEngine {
compiler.signatures().register(func_type) compiler.signatures().register(func_type)
} }
fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
let compiler = self.inner();
compiler.func_data().register(func_data)
}
/// Lookup a signature /// Lookup a signature
fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> { fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
let compiler = self.inner(); let compiler = self.inner();
@@ -234,6 +243,11 @@ pub struct NativeEngineInner {
/// performantly. /// performantly.
signatures: SignatureRegistry, signatures: SignatureRegistry,
/// The backing storage of `VMFuncRef`s. This centralized store ensures that 2
/// functions with the same `VMCallerCheckedAnyfunc` will have the same `VMFuncRef`.
/// It also guarantees that the `VMFuncRef`s stay valid until the engine is dropped.
func_data: Arc<FuncDataRegistry>,
/// The prefixer returns the a String to prefix each of /// The prefixer returns the a String to prefix each of
/// the functions in the shared object generated by the `NativeEngine`, /// the functions in the shared object generated by the `NativeEngine`,
/// so we can assure no collisions. /// so we can assure no collisions.
@@ -297,6 +311,11 @@ impl NativeEngineInner {
&self.signatures &self.signatures
} }
/// Shared func metadata registry.
pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
&self.func_data
}
pub(crate) fn is_cross_compiling(&self) -> bool { pub(crate) fn is_cross_compiling(&self) -> bool {
self.is_cross_compiling self.is_cross_compiling
} }

View File

@@ -27,7 +27,8 @@ use wasmer_types::{
TableIndex, TableIndex,
}; };
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex, VMTrampoline, FuncDataRegistry, FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex,
VMTrampoline,
}; };
/// A compiled wasm module, ready to be instantiated. /// A compiled wasm module, ready to be instantiated.
@@ -40,6 +41,7 @@ pub struct ObjectFileArtifact {
finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>, finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>, finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>, signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
func_data_registry: Arc<FuncDataRegistry>,
/// Length of the serialized metadata /// Length of the serialized metadata
metadata_length: usize, metadata_length: usize,
symbol_registry: ModuleMetadataSymbolRegistry, symbol_registry: ModuleMetadataSymbolRegistry,
@@ -278,6 +280,7 @@ impl ObjectFileArtifact {
finished_dynamic_function_trampolines: finished_dynamic_function_trampolines finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
.into_boxed_slice(), .into_boxed_slice(),
signatures: signatures.into_boxed_slice(), signatures: signatures.into_boxed_slice(),
func_data_registry: engine_inner.func_data().clone(),
metadata_length, metadata_length,
symbol_registry, symbol_registry,
}) })
@@ -317,11 +320,22 @@ impl ObjectFileArtifact {
let engine_inner = engine.inner(); let engine_inner = engine.inner();
let signature_registry = engine_inner.signatures(); let signature_registry = engine_inner.signatures();
let func_data_registry = engine_inner.func_data().clone();
let mut sig_map: BTreeMap<SignatureIndex, VMSharedSignatureIndex> = BTreeMap::new(); let mut sig_map: BTreeMap<SignatureIndex, VMSharedSignatureIndex> = BTreeMap::new();
let num_imported_functions = metadata.compile_info.module.num_imported_functions;
// set up the imported functions first...
for i in 0..num_imported_functions {
let sig_idx = metadata.compile_info.module.functions[FunctionIndex::new(i)];
let func_type = &metadata.compile_info.module.signatures[sig_idx];
let vm_shared_idx = signature_registry.register(&func_type);
sig_map.insert(sig_idx, vm_shared_idx);
}
// read finished functions in order now... // read finished functions in order now...
for i in 0..num_finished_functions { for i in 0..num_finished_functions {
let sig_idx = metadata.compile_info.module.functions[FunctionIndex::new(i)]; let local_func_idx = LocalFunctionIndex::new(i);
let func_idx = metadata.compile_info.module.func_index(local_func_idx);
let sig_idx = metadata.compile_info.module.functions[func_idx];
let func_type = &metadata.compile_info.module.signatures[sig_idx]; let func_type = &metadata.compile_info.module.signatures[sig_idx];
let vm_shared_idx = signature_registry.register(&func_type); let vm_shared_idx = signature_registry.register(&func_type);
sig_map.insert(sig_idx, vm_shared_idx); sig_map.insert(sig_idx, vm_shared_idx);
@@ -386,6 +400,7 @@ impl ObjectFileArtifact {
finished_dynamic_function_trampolines: finished_dynamic_function_trampolines finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
.into_boxed_slice(), .into_boxed_slice(),
signatures: signatures.into_boxed_slice(), signatures: signatures.into_boxed_slice(),
func_data_registry,
metadata_length: 0, metadata_length: 0,
symbol_registry, symbol_registry,
}) })
@@ -451,6 +466,10 @@ impl Artifact for ObjectFileArtifact {
&self.signatures &self.signatures
} }
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn preinstantiate(&self) -> Result<(), InstantiationError> { fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(()) Ok(())
} }

View File

@@ -10,7 +10,9 @@ use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use wasmer_types::Features; use wasmer_types::Features;
use wasmer_types::FunctionType; use wasmer_types::FunctionType;
use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex}; use wasmer_vm::{
FuncDataRegistry, SignatureRegistry, VMCallerCheckedAnyfunc, VMFuncRef, VMSharedSignatureIndex,
};
/// A WebAssembly `ObjectFile` Engine. /// A WebAssembly `ObjectFile` Engine.
#[derive(Clone, MemoryUsage)] #[derive(Clone, MemoryUsage)]
@@ -29,6 +31,7 @@ impl ObjectFileEngine {
inner: Arc::new(Mutex::new(ObjectFileEngineInner { inner: Arc::new(Mutex::new(ObjectFileEngineInner {
compiler: Some(compiler), compiler: Some(compiler),
signatures: SignatureRegistry::new(), signatures: SignatureRegistry::new(),
func_data: Arc::new(FuncDataRegistry::new()),
prefixer: None, prefixer: None,
features, features,
})), })),
@@ -58,6 +61,7 @@ impl ObjectFileEngine {
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
features: Features::default(), features: Features::default(),
signatures: SignatureRegistry::new(), signatures: SignatureRegistry::new(),
func_data: Arc::new(FuncDataRegistry::new()),
prefixer: None, prefixer: None,
})), })),
target: Arc::new(Target::default()), target: Arc::new(Target::default()),
@@ -104,6 +108,11 @@ impl Engine for ObjectFileEngine {
compiler.signatures().register(func_type) compiler.signatures().register(func_type)
} }
fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
let compiler = self.inner();
compiler.func_data().register(func_data)
}
/// Lookup a signature /// Lookup a signature
fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> { fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
let compiler = self.inner(); let compiler = self.inner();
@@ -180,6 +189,11 @@ pub struct ObjectFileEngineInner {
/// performantly. /// performantly.
signatures: SignatureRegistry, signatures: SignatureRegistry,
/// The backing storage of `VMFuncRef`s. This centralized store ensures that 2
/// functions with the same `VMCallerCheckedAnyfunc` will have the same `VMFuncRef`.
/// It also guarantees that the `VMFuncRef`s stay valid until the engine is dropped.
func_data: Arc<FuncDataRegistry>,
/// The prefixer returns the a String to prefix each of /// The prefixer returns the a String to prefix each of
/// the functions in the shared object generated by the `ObjectFileEngine`, /// the functions in the shared object generated by the `ObjectFileEngine`,
/// so we can assure no collisions. /// so we can assure no collisions.
@@ -232,4 +246,9 @@ impl ObjectFileEngineInner {
pub fn signatures(&self) -> &SignatureRegistry { pub fn signatures(&self) -> &SignatureRegistry {
&self.signatures &self.signatures
} }
/// Shared func metadata registry.
pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
&self.func_data
}
} }

View File

@@ -13,8 +13,8 @@ use wasmer_types::{
SignatureIndex, TableIndex, SignatureIndex, TableIndex,
}; };
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, InstanceAllocator, InstanceHandle, MemoryStyle, ModuleInfo, TableStyle, FuncDataRegistry, FunctionBodyPtr, InstanceAllocator, InstanceHandle, MemoryStyle, ModuleInfo,
VMSharedSignatureIndex, VMTrampoline, TableStyle, VMSharedSignatureIndex, VMTrampoline,
}; };
/// An `Artifact` is the product that the `Engine` /// An `Artifact` is the product that the `Engine`
@@ -67,6 +67,9 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
/// Returns the associated VM signatures for this `Artifact`. /// Returns the associated VM signatures for this `Artifact`.
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex>; fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex>;
/// Get the func data registry
fn func_data_registry(&self) -> &FuncDataRegistry;
/// Serializes an artifact into bytes /// Serializes an artifact into bytes
fn serialize(&self) -> Result<Vec<u8>, SerializeError>; fn serialize(&self) -> Result<Vec<u8>, SerializeError>;
@@ -143,6 +146,7 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
finished_globals, finished_globals,
imports, imports,
self.signatures().clone(), self.signatures().clone(),
self.func_data_registry(),
host_state, host_state,
import_function_envs, import_function_envs,
) )

View File

@@ -9,7 +9,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::{CompileError, Target}; use wasmer_compiler::{CompileError, Target};
use wasmer_types::FunctionType; use wasmer_types::FunctionType;
use wasmer_vm::VMSharedSignatureIndex; use wasmer_vm::{VMCallerCheckedAnyfunc, VMFuncRef, VMSharedSignatureIndex};
/// A unimplemented Wasmer `Engine`. /// A unimplemented Wasmer `Engine`.
/// ///
@@ -24,6 +24,9 @@ pub trait Engine: MemoryUsage {
/// Register a signature /// Register a signature
fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex; fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex;
/// Register a function's data.
fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef;
/// Lookup a signature /// Lookup a signature
fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType>; fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType>;

View File

@@ -23,3 +23,6 @@ std = ["serde/std"]
core = [] core = []
enable-rkyv = ["rkyv"] enable-rkyv = ["rkyv"]
enable-serde = ["serde"] enable-serde = ["serde"]
# experimental / in-development features
experimental-reference-types-extern-ref = []

295
lib/types/src/extern_ref.rs Normal file
View File

@@ -0,0 +1,295 @@
use std::any::Any;
use std::ptr;
use std::sync::atomic;
/// This type does not do reference counting automatically, reference counting can be done with
/// [`Self::ref_clone`] and [`Self::ref_drop`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct VMExternRef(*const VMExternRefInner);
impl VMExternRef {
/// The maximum number of references allowed to this data.
const MAX_REFCOUNT: usize = std::usize::MAX - 1;
/// Checks if the given ExternRef is null.
pub fn is_null(&self) -> bool {
self.0.is_null()
}
/// New null extern ref
pub const fn null() -> Self {
Self(ptr::null())
}
/// Get a bit-level representation of an externref.
/// For internal use for packing / unpacking it for calling functions.
pub(crate) fn to_binary(self) -> i128 {
self.0 as i128
}
/// Create an externref from bit-level representation.
/// For internal use for packing / unpacking it for calling functions.
///
/// # Safety
/// The pointer is assumed valid or null. Passing arbitrary data to this function will
/// result in undefined behavior. It is the caller's responsibility to verify that only
/// valid externref bit patterns are passed to this function.
pub(crate) unsafe fn from_binary(bits: i128) -> Self {
Self(bits as usize as *const _)
}
/// Make a new extern reference
pub fn new<T>(value: T) -> Self
where
T: Any + Send + Sync + 'static + Sized,
{
Self(Box::into_raw(Box::new(VMExternRefInner::new::<T>(value))))
}
/// Try to downcast to the given value
pub fn downcast<T>(&self) -> Option<&T>
where
T: Any + Send + Sync + 'static + Sized,
{
if self.is_null() {
return None;
}
unsafe {
let inner = &*self.0;
inner.data.downcast_ref::<T>()
}
}
/// Panic if the ref count gets too high.
#[track_caller]
fn sanity_check_ref_count(old_size: usize, growth_amount: usize) {
// If we exceed 18_446_744_073_709_551_614 references on a 64bit system (or
// 2_147_483_646 references on a 32bit system) then we either live in a future with
// magic technology or we have a bug in our ref counting logic (i.e. a leak).
// Either way, the best course of action is to terminate the program and update
// some code on our side.
//
// Note to future readers: exceeding `usize` ref count is trivially provable as a
// bug on systems that can address `usize` sized memory blocks or smaller because
// the reference itself is at least `usize` in size and all virtual memory would be
// taken by references to the data leaving no room for the data itself.
if old_size
.checked_add(growth_amount)
.map(|v| v > Self::MAX_REFCOUNT)
.unwrap_or(true)
{
panic!("Too many references to `ExternRef`");
}
}
/// A low-level function to increment the strong-count a given number of times.
///
/// This is used as an optimization when implementing some low-level VM primitives.
/// If you're using this type directly for whatever reason, you probably want
/// [`Self::ref_clone`] instead.
pub fn ref_inc_by(&self, val: usize) {
if self.0.is_null() {
return;
}
let old_size = unsafe {
let ref_inner = &*self.0;
ref_inner.increment_ref_count(val)
};
Self::sanity_check_ref_count(old_size, val);
}
/// A deep copy of the reference, increments the strong count.
pub fn ref_clone(&self) -> Self {
if self.0.is_null() {
return Self(self.0);
}
let old_size = unsafe {
let ref_inner = &*self.0;
ref_inner.increment_ref_count(1)
};
// See comments in [`Self::sanity_check_ref_count`] for more information.
if old_size > Self::MAX_REFCOUNT {
panic!("Too many references to `ExternRef`");
}
Self(self.0)
}
/// Does an inner drop, decrementing the strong count
pub fn ref_drop(&mut self) {
if !self.0.is_null() {
unsafe {
let should_drop = {
let ref_inner: &VMExternRefInner = &*self.0;
ref_inner.decrement_and_drop()
};
if should_drop {
let _ = Box::from_raw(self.0 as *mut VMExternRefInner);
}
}
}
}
#[allow(dead_code)]
/// Get the number of strong references to this data.
fn strong_count(&self) -> usize {
if self.0.is_null() {
0
} else {
unsafe { (&*self.0).strong.load(atomic::Ordering::SeqCst) }
}
}
}
#[derive(Debug)]
#[repr(C)]
pub(crate) struct VMExternRefInner {
strong: atomic::AtomicUsize,
/// Do something obviously correct to get started. This can "easily" be improved
/// to be an inline allocation later as the logic is fully encapsulated.
data: Box<dyn Any + Send + Sync + 'static>,
}
impl VMExternRefInner {
fn new<T>(value: T) -> Self
where
T: Any + Send + Sync + Sized + 'static,
{
Self {
strong: atomic::AtomicUsize::new(1),
data: Box::new(value),
}
}
/// Increments the reference count.
/// Returns the old value.
fn increment_ref_count(&self, val: usize) -> usize {
// Using a relaxed ordering is alright here, as knowledge of
// the original reference prevents other threads from
// erroneously deleting the object.
//
// As explained in the [Boost documentation][1]:
//
// > Increasing the reference counter can always be done with
// > `memory_order_relaxed`: New references to an object can
// > only be formed from an existing reference, and passing an
// > existing reference from one thread to another must already
// > provide any required synchronization.
//
// [1]: https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
self.strong.fetch_add(val, atomic::Ordering::Relaxed)
}
/// Decrement the count and drop the data if the count hits 0
/// returns `true` if the containing allocation should be dropped
fn decrement_and_drop(&self) -> bool {
// Because `fetch_sub` is already atomic, we do not need to
// synchronize with other thread.
if self.strong.fetch_sub(1, atomic::Ordering::Release) != 1 {
return false;
}
// This fence is needed to prevent reordering of use of the data and
// deletion of the data. Because it is marked `Release`, the decreasing
// of the reference count synchronizes with this `Acquire` fence. This
// means that use of the data happens before decreasing the reference
// count, which happens before this fence, which happens before the
// deletion of the data.
//
// As explained in the [Boost documentation][1]:
//
// > It is important to enforce any possible access to the object in one
// > thread (through an existing reference) to *happen before* deleting
// > the object in a different thread. This is achieved by a "release"
// > operation after dropping a reference (any access to the object
// > through this reference must obviously happened before), and an
// > "acquire" operation before deleting the object.
//
// [1]: https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
atomic::fence(atomic::Ordering::Acquire);
return true;
}
}
#[derive(Debug, PartialEq, Eq)]
#[repr(transparent)]
/// An opaque reference to some data. This reference can be passed through Wasm.
pub struct ExternRef {
inner: VMExternRef,
}
impl Clone for ExternRef {
fn clone(&self) -> Self {
Self {
inner: self.inner.ref_clone(),
}
}
}
impl Drop for ExternRef {
fn drop(&mut self) {
self.inner.ref_drop()
}
}
impl ExternRef {
/// Checks if the given ExternRef is null.
pub fn is_null(&self) -> bool {
self.inner.is_null()
}
/// New null extern ref
pub fn null() -> Self {
Self {
inner: VMExternRef::null(),
}
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
/// Make a new extern reference
pub fn new<T>(value: T) -> Self
where
T: Any + Send + Sync + 'static + Sized,
{
Self {
inner: VMExternRef::new(value),
}
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
/// Try to downcast to the given value
pub fn downcast<T>(&self) -> Option<&T>
where
T: Any + Send + Sync + 'static + Sized,
{
self.inner.downcast::<T>()
}
#[cfg(feature = "experimental-reference-types-extern-ref")]
/// Get the number of strong references to this data.
pub fn strong_count(&self) -> usize {
self.inner.strong_count()
}
}
impl From<VMExternRef> for ExternRef {
fn from(other: VMExternRef) -> Self {
Self { inner: other }
}
}
impl From<ExternRef> for VMExternRef {
fn from(other: ExternRef) -> Self {
let out = other.inner;
// We want to make this transformation without decrementing the count.
std::mem::forget(other);
out
}
}

View File

@@ -42,7 +42,8 @@ impl Features {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
threads: false, threads: false,
reference_types: false, // Reference types should be on by default
reference_types: true,
simd: false, simd: false,
// Bulk Memory should be on by default // Bulk Memory should be on by default
bulk_memory: true, bulk_memory: true,
@@ -76,16 +77,14 @@ impl Features {
/// Configures whether the WebAssembly reference types proposal will be /// Configures whether the WebAssembly reference types proposal will be
/// enabled. /// enabled.
/// ///
/// The [WebAssembly reference types proposal][proposal] is not currently /// The [WebAssembly reference types proposal][proposal] is now
/// fully standardized and is undergoing development. Support for this /// fully standardized and enabled by default.
/// feature can be enabled through this method for appropriate WebAssembly
/// modules.
/// ///
/// This feature gates items such as the `externref` type and multiple tables /// This feature gates items such as the `externref` type and multiple tables
/// being in a module. Note that enabling the reference types feature will /// being in a module. Note that enabling the reference types feature will
/// also enable the bulk memory feature. /// also enable the bulk memory feature.
/// ///
/// This is `false` by default. /// This is `true` by default.
/// ///
/// [proposal]: https://github.com/webassembly/reference-types /// [proposal]: https://github.com/webassembly/reference-types
pub fn reference_types(&mut self, enable: bool) -> &mut Self { pub fn reference_types(&mut self, enable: bool) -> &mut Self {
@@ -119,15 +118,13 @@ impl Features {
/// Configures whether the WebAssembly bulk memory operations proposal will /// Configures whether the WebAssembly bulk memory operations proposal will
/// be enabled. /// be enabled.
/// ///
/// The [WebAssembly bulk memory operations proposal][proposal] is not /// The [WebAssembly bulk memory operations proposal][proposal] is now
/// currently fully standardized and is undergoing development. /// fully standardized and enabled by default.
/// Support for this feature can be enabled through this method for
/// appropriate WebAssembly modules.
/// ///
/// This feature gates items such as the `memory.copy` instruction, passive /// This feature gates items such as the `memory.copy` instruction, passive
/// data/table segments, etc, being in a module. /// data/table segments, etc, being in a module.
/// ///
/// This is `false` by default. /// This is `true` by default.
/// ///
/// [proposal]: https://github.com/webassembly/bulk-memory-operations /// [proposal]: https://github.com/webassembly/bulk-memory-operations
pub fn bulk_memory(&mut self, enable: bool) -> &mut Self { pub fn bulk_memory(&mut self, enable: bool) -> &mut Self {
@@ -177,10 +174,10 @@ impl Features {
self self
} }
/// Configures whether the WebAssembly tail-call proposal will /// Configures whether the WebAssembly module linking proposal will
/// be enabled. /// be enabled.
/// ///
/// The [WebAssembly tail-call proposal][proposal] is not /// The [WebAssembly module linking proposal][proposal] is not
/// currently fully standardized and is undergoing development. /// currently fully standardized and is undergoing development.
/// Support for this feature can be enabled through this method for /// Support for this feature can be enabled through this method for
/// appropriate WebAssembly modules. /// appropriate WebAssembly modules.
@@ -251,7 +248,7 @@ mod test_features {
default, default,
Features { Features {
threads: false, threads: false,
reference_types: false, reference_types: true,
simd: false, simd: false,
bulk_memory: true, bulk_memory: true,
multi_value: true, multi_value: true,

View File

@@ -56,18 +56,19 @@ pub mod lib {
#[cfg(feature = "enable-rkyv")] #[cfg(feature = "enable-rkyv")]
mod archives; mod archives;
mod extern_ref;
mod features; mod features;
mod indexes; mod indexes;
mod initializers; mod initializers;
mod memory_view; mod memory_view;
mod native; mod native;
mod r#ref;
mod types; mod types;
mod units; mod units;
mod values; mod values;
/// The entity module, with common helpers for Rust structures /// The entity module, with common helpers for Rust structures
pub mod entity; pub mod entity;
pub use crate::extern_ref::{ExternRef, VMExternRef};
pub use crate::features::Features; pub use crate::features::Features;
pub use crate::indexes::{ pub use crate::indexes::{
CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, ImportIndex, CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, ImportIndex,
@@ -79,11 +80,10 @@ pub use crate::initializers::{
}; };
pub use crate::memory_view::{Atomically, MemoryView}; pub use crate::memory_view::{Atomically, MemoryView};
pub use crate::native::{NativeWasmType, ValueType}; pub use crate::native::{NativeWasmType, ValueType};
pub use crate::r#ref::{ExternRef, HostInfo, HostRef};
pub use crate::units::{ pub use crate::units::{
Bytes, PageCountOutOfRange, Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, Bytes, PageCountOutOfRange, Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
}; };
pub use crate::values::Value; pub use crate::values::{Value, WasmValueType};
pub use types::{ pub use types::{
ExportType, ExternType, FunctionType, GlobalInit, GlobalType, ImportType, MemoryType, ExportType, ExternType, FunctionType, GlobalInit, GlobalType, ImportType, MemoryType,
Mutability, TableType, Type, V128, Mutability, TableType, Type, V128,

View File

@@ -1,9 +1,10 @@
//! This module permits to create native functions //! This module permits to create native functions
//! easily in Rust, thanks to its advanced typing system. //! easily in Rust, thanks to its advanced typing system.
use crate::extern_ref::VMExternRef;
use crate::lib::std::fmt; use crate::lib::std::fmt;
use crate::types::Type; use crate::types::Type;
use crate::values::Value; use crate::values::{Value, WasmValueType};
/// `NativeWasmType` represents a Wasm type that has a direct /// `NativeWasmType` represents a Wasm type that has a direct
/// representation on the host (hence the “native” term). /// representation on the host (hence the “native” term).
@@ -37,10 +38,13 @@ pub trait NativeWasmType: Sized {
fn to_binary(self) -> i128; fn to_binary(self) -> i128;
/// Convert self to a `Value`. /// Convert self to a `Value`.
fn to_value<T>(self) -> Value<T> { fn to_value<T: WasmValueType>(self) -> Value<T> {
let binary = self.to_binary(); let binary = self.to_binary();
// we need a store, we're just hoping we don't actually use it via funcref
// TODO(reftypes): we need an actual solution here
let hack = 3;
unsafe { Value::read_value_from(&binary, Self::WASM_TYPE) } unsafe { Value::read_value_from(&hack, &binary, Self::WASM_TYPE) }
} }
/// Convert to self from i128 binary representation. /// Convert to self from i128 binary representation.
@@ -172,6 +176,32 @@ impl NativeWasmType for u128 {
} }
} }
impl NativeWasmType for VMExternRef {
const WASM_TYPE: Type = Type::ExternRef;
type Abi = Self;
#[inline]
fn from_abi(abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self) -> Self::Abi {
self
}
#[inline]
fn to_binary(self) -> i128 {
self.to_binary()
}
#[inline]
fn from_binary(bits: i128) -> Self {
// TODO(reftypes): ensure that the safety invariants are actually upheld here
unsafe { Self::from_binary(bits) }
}
}
#[cfg(test)] #[cfg(test)]
mod test_native_type { mod test_native_type {
use super::*; use super::*;

View File

@@ -1,267 +0,0 @@
#![allow(missing_docs)]
use crate::lib::std::any::Any;
use crate::lib::std::boxed::Box;
use crate::lib::std::cell::{self, RefCell};
use crate::lib::std::fmt;
use crate::lib::std::hash;
use crate::lib::std::rc::{Rc, Weak};
pub trait HostInfo {
fn finalize(&mut self) {}
}
trait InternalRefBase: Any {
fn as_any(&self) -> &dyn Any;
fn host_info(&self) -> Option<cell::RefMut<Box<dyn HostInfo>>>;
fn set_host_info(&self, info: Option<Box<dyn HostInfo>>);
fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool;
}
#[derive(Clone)]
pub struct InternalRef(Rc<dyn InternalRefBase>);
impl InternalRef {
pub fn is_ref<T: 'static>(&self) -> bool {
let r = self.0.as_any();
Any::is::<HostRef<T>>(r)
}
pub fn get_ref<T: 'static>(&self) -> HostRef<T> {
let r = self.0.as_any();
r.downcast_ref::<HostRef<T>>()
.expect("reference is not T type")
.clone()
}
}
struct AnyAndHostInfo {
any: Box<dyn Any>,
host_info: Option<Box<dyn HostInfo>>,
}
impl Drop for AnyAndHostInfo {
fn drop(&mut self) {
if let Some(info) = &mut self.host_info {
info.finalize();
}
}
}
#[derive(Clone)]
pub struct OtherRef(Rc<RefCell<AnyAndHostInfo>>);
/// Represents an opaque reference to any data within WebAssembly.
#[derive(Clone)]
pub enum ExternRef {
/// A reference to no data.
Null,
/// A reference to data stored internally.
Ref(InternalRef),
/// A reference to data located outside.
Other(OtherRef),
}
impl hash::Hash for ExternRef {
fn hash<H: hash::Hasher>(&self, _state: &mut H) {}
}
impl PartialEq for ExternRef {
fn eq(&self, other: &Self) -> bool {
// The `ExternRef`s are the same if they point to the same value
self.ptr_eq(other)
}
}
impl Eq for ExternRef {}
impl ExternRef {
/// Creates a new instance of `ExternRef` from `Box<dyn Any>`.
pub fn new(data: Box<dyn Any>) -> Self {
let info = AnyAndHostInfo {
any: data,
host_info: None,
};
Self::Other(OtherRef(Rc::new(RefCell::new(info))))
}
/// Creates a `Null` reference.
pub fn null() -> Self {
Self::Null
}
/// Returns the data stored in the reference if available.
///
/// # Panics
///
/// Panics if the variant isn't `ExternRef::Other`.
pub fn data(&self) -> cell::Ref<Box<dyn Any>> {
match self {
Self::Other(OtherRef(r)) => cell::Ref::map(r.borrow(), |r| &r.any),
_ => panic!("expected ExternRef::Other"),
}
}
/// Returns true if the two `ExternRef<T>`'s point to the same value (not just
/// values that compare as equal).
pub fn ptr_eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Null, Self::Null) => true,
(Self::Ref(InternalRef(ref a)), Self::Ref(InternalRef(ref b))) => a.ptr_eq(b.as_ref()),
(Self::Other(OtherRef(ref a)), Self::Other(OtherRef(ref b))) => Rc::ptr_eq(a, b),
_ => false,
}
}
/// Returns a mutable reference to the host information if available.
///
/// # Panics
///
/// Panics if `ExternRef` is already borrowed or `ExternRef` is `Null`.
pub fn host_info(&self) -> Option<cell::RefMut<Box<dyn HostInfo>>> {
match self {
Self::Null => panic!("null"),
Self::Ref(r) => r.0.host_info(),
Self::Other(r) => {
let info = cell::RefMut::map(r.0.borrow_mut(), |b| &mut b.host_info);
if info.is_none() {
return None;
}
Some(cell::RefMut::map(info, |info| info.as_mut().unwrap()))
}
}
}
/// Sets the host information for an `ExternRef`.
///
/// # Panics
///
/// Panics if `ExternRef` is already borrowed or `ExternRef` is `Null`.
pub fn set_host_info(&self, info: Option<Box<dyn HostInfo>>) {
match self {
Self::Null => panic!("null"),
Self::Ref(r) => r.0.set_host_info(info),
Self::Other(r) => {
r.0.borrow_mut().host_info = info;
}
}
}
}
impl fmt::Debug for ExternRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Null => write!(f, "null"),
Self::Ref(_) => write!(f, "externref"),
Self::Other(_) => write!(f, "other ref"),
}
}
}
struct ContentBox<T> {
content: T,
host_info: Option<Box<dyn HostInfo>>,
externref_data: Weak<dyn InternalRefBase>,
}
impl<T> Drop for ContentBox<T> {
fn drop(&mut self) {
if let Some(info) = &mut self.host_info {
info.finalize();
}
}
}
/// Represents a piece of data located in the host environment.
pub struct HostRef<T>(Rc<RefCell<ContentBox<T>>>);
impl<T: 'static> HostRef<T> {
/// Creates a new `HostRef<T>` from `T`.
pub fn new(item: T) -> Self {
let externref_data: Weak<Self> = Weak::new();
let content = ContentBox {
content: item,
host_info: None,
externref_data,
};
Self(Rc::new(RefCell::new(content)))
}
/// Immutably borrows the wrapped data.
///
/// # Panics
///
/// Panics if the value is currently mutably borrowed.
pub fn borrow(&self) -> cell::Ref<T> {
cell::Ref::map(self.0.borrow(), |b| &b.content)
}
/// Mutably borrows the wrapped data.
///
/// # Panics
///
/// Panics if the `HostRef<T>` is already borrowed.
pub fn borrow_mut(&self) -> cell::RefMut<T> {
cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.content)
}
/// Returns true if the two `HostRef<T>`'s point to the same value (not just
/// values that compare as equal).
pub fn ptr_eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
/// Returns an opaque reference to the wrapped data in the form of
/// an `ExternRef`.
///
/// # Panics
///
/// Panics if `HostRef<T>` is already mutably borrowed.
pub fn externref(&self) -> ExternRef {
let r = self.0.borrow_mut().externref_data.upgrade();
if let Some(r) = r {
return ExternRef::Ref(InternalRef(r));
}
let externref_data: Rc<dyn InternalRefBase> = Rc::new(self.clone());
self.0.borrow_mut().externref_data = Rc::downgrade(&externref_data);
ExternRef::Ref(InternalRef(externref_data))
}
}
impl<T: 'static> InternalRefBase for HostRef<T> {
fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool {
if let Some(other) = other.as_any().downcast_ref() {
self.ptr_eq(other)
} else {
false
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn host_info(&self) -> Option<cell::RefMut<Box<dyn HostInfo>>> {
let info = cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.host_info);
if info.is_none() {
return None;
}
Some(cell::RefMut::map(info, |info| info.as_mut().unwrap()))
}
fn set_host_info(&self, info: Option<Box<dyn HostInfo>>) {
self.0.borrow_mut().host_info = info;
}
}
impl<T> Clone for HostRef<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: fmt::Debug> fmt::Debug for HostRef<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Ref(")?;
self.0.borrow().content.fmt(f)?;
write!(f, ")")
}
}

View File

@@ -5,7 +5,7 @@ use crate::lib::std::format;
use crate::lib::std::string::{String, ToString}; use crate::lib::std::string::{String, ToString};
use crate::lib::std::vec::Vec; use crate::lib::std::vec::Vec;
use crate::units::Pages; use crate::units::Pages;
use crate::values::Value; use crate::values::{Value, WasmValueType};
use loupe::{MemoryUsage, MemoryUsageTracker}; use loupe::{MemoryUsage, MemoryUsageTracker};
#[cfg(feature = "enable-rkyv")] #[cfg(feature = "enable-rkyv")]
@@ -437,6 +437,9 @@ pub enum GlobalInit {
V128Const(V128), V128Const(V128),
/// A `global.get` of another global. /// A `global.get` of another global.
GetGlobal(GlobalIndex), GetGlobal(GlobalIndex),
// TODO(reftypes): `ref.null func` and `ref.null extern` seem to be 2 different
// things: we need to handle both. Perhaps this handled in context by the
// global knowing its own type?
/// A `ref.null`. /// A `ref.null`.
RefNullConst, RefNullConst,
/// A `ref.func <index>`. /// A `ref.func <index>`.
@@ -447,7 +450,7 @@ impl Eq for GlobalInit {}
impl GlobalInit { impl GlobalInit {
/// Get the `GlobalInit` from a given `Value` /// Get the `GlobalInit` from a given `Value`
pub fn from_value<T>(value: Value<T>) -> Self { pub fn from_value<T: WasmValueType>(value: Value<T>) -> Self {
match value { match value {
Value::I32(i) => Self::I32Const(i), Value::I32(i) => Self::I32Const(i),
Value::I64(i) => Self::I64Const(i), Value::I64(i) => Self::I64Const(i),
@@ -457,7 +460,7 @@ impl GlobalInit {
} }
} }
/// Get the `Value` from the Global init value /// Get the `Value` from the Global init value
pub fn to_value<T>(&self) -> Value<T> { pub fn to_value<T: WasmValueType>(&self) -> Value<T> {
match self { match self {
Self::I32Const(i) => Value::I32(*i), Self::I32Const(i) => Value::I32(*i),
Self::I64Const(i) => Value::I64(*i), Self::I64Const(i) => Value::I64(*i),

View File

@@ -1,8 +1,8 @@
use crate::extern_ref::ExternRef;
use crate::lib::std::convert::TryFrom; use crate::lib::std::convert::TryFrom;
use crate::lib::std::fmt; use crate::lib::std::fmt;
use crate::lib::std::ptr; use crate::lib::std::ptr;
use crate::lib::std::string::{String, ToString}; use crate::lib::std::string::{String, ToString};
use crate::r#ref::ExternRef;
use crate::types::Type; use crate::types::Type;
/// Possible runtime values that a WebAssembly module can either consume or /// Possible runtime values that a WebAssembly module can either consume or
@@ -31,7 +31,7 @@ pub enum Value<T> {
ExternRef(ExternRef), ExternRef(ExternRef),
/// A first-class reference to a WebAssembly function. /// A first-class reference to a WebAssembly function.
FuncRef(T), FuncRef(Option<T>),
/// A 128-bit number /// A 128-bit number
V128(u128), V128(u128),
@@ -61,7 +61,32 @@ macro_rules! accessors {
)*) )*)
} }
impl<T> Value<T> { /// Trait for reading and writing Wasm values into binary for use on the layer
/// between the API and the VM internals, specifically with `wasmer_types::Value`.
pub trait WasmValueType: std::fmt::Debug + 'static {
/// Write the value
unsafe fn write_value_to(&self, p: *mut i128);
/// read the value
// TODO(reftypes): passing the store as `dyn Any` is a hack to work around the
// structure of our crates. We need to talk about the store in the rest of the
// VM (for example where this method is used) but cannot do so. Fixing this
// may be non-trivial.
unsafe fn read_value_from(store: &dyn std::any::Any, p: *const i128) -> Self;
}
impl WasmValueType for () {
unsafe fn write_value_to(&self, _p: *mut i128) {}
unsafe fn read_value_from(_store: &dyn std::any::Any, _p: *const i128) -> Self {
()
}
}
impl<T> Value<T>
where
T: WasmValueType,
{
/// Returns a null `externref` value. /// Returns a null `externref` value.
pub fn null() -> Self { pub fn null() -> Self {
Self::ExternRef(ExternRef::null()) Self::ExternRef(ExternRef::null())
@@ -93,7 +118,10 @@ impl<T> Value<T> {
Self::F32(u) => ptr::write(p as *mut f32, *u), Self::F32(u) => ptr::write(p as *mut f32, *u),
Self::F64(u) => ptr::write(p as *mut f64, *u), Self::F64(u) => ptr::write(p as *mut f64, *u),
Self::V128(b) => ptr::write(p as *mut u128, *b), Self::V128(b) => ptr::write(p as *mut u128, *b),
_ => unimplemented!("Value::write_value_to"), Self::FuncRef(Some(b)) => T::write_value_to(b, p),
Self::FuncRef(None) => ptr::write(p as *mut usize, 0),
// TODO(reftypes): review clone here
Self::ExternRef(extern_ref) => ptr::write(p as *mut ExternRef, extern_ref.clone()),
} }
} }
@@ -103,14 +131,25 @@ impl<T> Value<T> {
/// `p` must be: /// `p` must be:
/// - Properly aligned to the specified `ty`'s Rust equivalent /// - Properly aligned to the specified `ty`'s Rust equivalent
/// - Non-null and pointing to valid memory /// - Non-null and pointing to valid memory
pub unsafe fn read_value_from(p: *const i128, ty: Type) -> Self { pub unsafe fn read_value_from(store: &dyn std::any::Any, p: *const i128, ty: Type) -> Self {
match ty { match ty {
Type::I32 => Self::I32(ptr::read(p as *const i32)), Type::I32 => Self::I32(ptr::read(p as *const i32)),
Type::I64 => Self::I64(ptr::read(p as *const i64)), Type::I64 => Self::I64(ptr::read(p as *const i64)),
Type::F32 => Self::F32(ptr::read(p as *const f32)), Type::F32 => Self::F32(ptr::read(p as *const f32)),
Type::F64 => Self::F64(ptr::read(p as *const f64)), Type::F64 => Self::F64(ptr::read(p as *const f64)),
Type::V128 => Self::V128(ptr::read(p as *const u128)), Type::V128 => Self::V128(ptr::read(p as *const u128)),
_ => unimplemented!("Value::read_value_from"), Type::FuncRef => {
// We do the null check ourselves
if (*(p as *const usize)) == 0 {
Self::FuncRef(None)
} else {
Self::FuncRef(Some(T::read_value_from(store, p)))
}
}
Type::ExternRef => {
let extern_ref = (&*(p as *const ExternRef)).clone();
Self::ExternRef(extern_ref)
}
} }
} }
@@ -120,33 +159,16 @@ impl<T> Value<T> {
(I64(i64) i64 unwrap_i64 *e) (I64(i64) i64 unwrap_i64 *e)
(F32(f32) f32 unwrap_f32 *e) (F32(f32) f32 unwrap_f32 *e)
(F64(f64) f64 unwrap_f64 *e) (F64(f64) f64 unwrap_f64 *e)
(FuncRef(&T) funcref unwrap_funcref e) (ExternRef(ExternRef) externref unwrap_externref e.clone())
(FuncRef(&Option<T>) funcref unwrap_funcref e)
(V128(u128) v128 unwrap_v128 *e) (V128(u128) v128 unwrap_v128 *e)
} }
/// Attempt to access the underlying value of this `Value`, returning
/// `None` if it is not the correct type.
///
/// This will return `Some` for both the `ExternRef` and `FuncRef` types.
pub fn externref(&self) -> Option<ExternRef> {
match self {
Self::ExternRef(e) => Some(e.clone()),
_ => None,
}
}
/// Returns the underlying value of this `Value`, panicking if it's the
/// wrong type.
///
/// # Panics
///
/// Panics if `self` is not of the right type.
pub fn unwrap_externref(&self) -> ExternRef {
self.externref().expect("expected externref")
}
} }
impl<T> fmt::Debug for Value<T> { impl<T> fmt::Debug for Value<T>
where
T: WasmValueType,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::I32(v) => write!(f, "I32({:?})", v), Self::I32(v) => write!(f, "I32({:?})", v),
@@ -154,13 +176,17 @@ impl<T> fmt::Debug for Value<T> {
Self::F32(v) => write!(f, "F32({:?})", v), Self::F32(v) => write!(f, "F32({:?})", v),
Self::F64(v) => write!(f, "F64({:?})", v), Self::F64(v) => write!(f, "F64({:?})", v),
Self::ExternRef(v) => write!(f, "ExternRef({:?})", v), Self::ExternRef(v) => write!(f, "ExternRef({:?})", v),
Self::FuncRef(_) => write!(f, "FuncRef"), Self::FuncRef(None) => write!(f, "Null FuncRef"),
Self::FuncRef(Some(v)) => write!(f, "FuncRef({:?})", v),
Self::V128(v) => write!(f, "V128({:?})", v), Self::V128(v) => write!(f, "V128({:?})", v),
} }
} }
} }
impl<T> ToString for Value<T> { impl<T> ToString for Value<T>
where
T: WasmValueType,
{
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
Self::I32(v) => v.to_string(), Self::I32(v) => v.to_string(),
@@ -174,45 +200,66 @@ impl<T> ToString for Value<T> {
} }
} }
impl<T> From<i32> for Value<T> { impl<T> From<i32> for Value<T>
where
T: WasmValueType,
{
fn from(val: i32) -> Self { fn from(val: i32) -> Self {
Self::I32(val) Self::I32(val)
} }
} }
impl<T> From<u32> for Value<T> { impl<T> From<u32> for Value<T>
where
T: WasmValueType,
{
fn from(val: u32) -> Self { fn from(val: u32) -> Self {
// In Wasm integers are sign-agnostic, so i32 is basically a 4 byte storage we can use for signed or unsigned 32-bit integers. // In Wasm integers are sign-agnostic, so i32 is basically a 4 byte storage we can use for signed or unsigned 32-bit integers.
Self::I32(val as i32) Self::I32(val as i32)
} }
} }
impl<T> From<i64> for Value<T> { impl<T> From<i64> for Value<T>
where
T: WasmValueType,
{
fn from(val: i64) -> Self { fn from(val: i64) -> Self {
Self::I64(val) Self::I64(val)
} }
} }
impl<T> From<u64> for Value<T> { impl<T> From<u64> for Value<T>
where
T: WasmValueType,
{
fn from(val: u64) -> Self { fn from(val: u64) -> Self {
// In Wasm integers are sign-agnostic, so i64 is basically an 8 byte storage we can use for signed or unsigned 64-bit integers. // In Wasm integers are sign-agnostic, so i64 is basically an 8 byte storage we can use for signed or unsigned 64-bit integers.
Self::I64(val as i64) Self::I64(val as i64)
} }
} }
impl<T> From<f32> for Value<T> { impl<T> From<f32> for Value<T>
where
T: WasmValueType,
{
fn from(val: f32) -> Self { fn from(val: f32) -> Self {
Self::F32(val) Self::F32(val)
} }
} }
impl<T> From<f64> for Value<T> { impl<T> From<f64> for Value<T>
where
T: WasmValueType,
{
fn from(val: f64) -> Self { fn from(val: f64) -> Self {
Self::F64(val) Self::F64(val)
} }
} }
impl<T> From<ExternRef> for Value<T> { impl<T> From<ExternRef> for Value<T>
where
T: WasmValueType,
{
fn from(val: ExternRef) -> Self { fn from(val: ExternRef) -> Self {
Self::ExternRef(val) Self::ExternRef(val)
} }
@@ -229,7 +276,10 @@ const NOT_I64: &str = "Value is not of Wasm type i64";
const NOT_F32: &str = "Value is not of Wasm type f32"; const NOT_F32: &str = "Value is not of Wasm type f32";
const NOT_F64: &str = "Value is not of Wasm type f64"; const NOT_F64: &str = "Value is not of Wasm type f64";
impl<T> TryFrom<Value<T>> for i32 { impl<T> TryFrom<Value<T>> for i32
where
T: WasmValueType,
{
type Error = &'static str; type Error = &'static str;
fn try_from(value: Value<T>) -> Result<Self, Self::Error> { fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
@@ -237,7 +287,10 @@ impl<T> TryFrom<Value<T>> for i32 {
} }
} }
impl<T> TryFrom<Value<T>> for u32 { impl<T> TryFrom<Value<T>> for u32
where
T: WasmValueType,
{
type Error = &'static str; type Error = &'static str;
fn try_from(value: Value<T>) -> Result<Self, Self::Error> { fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
@@ -245,7 +298,10 @@ impl<T> TryFrom<Value<T>> for u32 {
} }
} }
impl<T> TryFrom<Value<T>> for i64 { impl<T> TryFrom<Value<T>> for i64
where
T: WasmValueType,
{
type Error = &'static str; type Error = &'static str;
fn try_from(value: Value<T>) -> Result<Self, Self::Error> { fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
@@ -253,7 +309,10 @@ impl<T> TryFrom<Value<T>> for i64 {
} }
} }
impl<T> TryFrom<Value<T>> for u64 { impl<T> TryFrom<Value<T>> for u64
where
T: WasmValueType,
{
type Error = &'static str; type Error = &'static str;
fn try_from(value: Value<T>) -> Result<Self, Self::Error> { fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
@@ -261,7 +320,10 @@ impl<T> TryFrom<Value<T>> for u64 {
} }
} }
impl<T> TryFrom<Value<T>> for f32 { impl<T> TryFrom<Value<T>> for f32
where
T: WasmValueType,
{
type Error = &'static str; type Error = &'static str;
fn try_from(value: Value<T>) -> Result<Self, Self::Error> { fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
@@ -269,7 +331,10 @@ impl<T> TryFrom<Value<T>> for f32 {
} }
} }
impl<T> TryFrom<Value<T>> for f64 { impl<T> TryFrom<Value<T>> for f64
where
T: WasmValueType,
{
type Error = &'static str; type Error = &'static str;
fn try_from(value: Value<T>) -> Result<Self, Self::Error> { fn try_from(value: Value<T>) -> Result<Self, Self::Error> {

View File

@@ -0,0 +1,121 @@
//! A registry for `VMFuncRef`s. This allows us to deduplicate funcrefs so that
//! identical `VMCallerCheckedAnyfunc`s will give us identical funcrefs.
//!
//! This registry also helps ensure that the `VMFuncRef`s can stay valid for as
//! long as we need them to.
use crate::vmcontext::VMCallerCheckedAnyfunc;
use loupe::MemoryUsage;
use std::collections::HashMap;
use std::sync::Mutex;
/// The registry that holds the values that `VMFuncRef`s point to.
#[derive(Debug, MemoryUsage)]
pub struct FuncDataRegistry {
// This structure is stored in an `Engine` and is intended to be shared
// across many instances. Ideally instances can themselves be sent across
// threads, and ideally we can compile across many threads. As a result we
// use interior mutability here with a lock to avoid having callers to
// externally synchronize calls to compilation.
inner: Mutex<Inner>,
}
// We use raw pointers but the data never moves, so it's not a problem
unsafe impl Send for FuncDataRegistry {}
unsafe impl Sync for FuncDataRegistry {}
/// A function reference. A single word that points to metadata about a function.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, MemoryUsage)]
pub struct VMFuncRef(pub(crate) *const VMCallerCheckedAnyfunc);
impl wasmer_types::NativeWasmType for VMFuncRef {
const WASM_TYPE: wasmer_types::Type = wasmer_types::Type::FuncRef;
type Abi = Self;
#[inline]
fn from_abi(abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self) -> Self::Abi {
self
}
#[inline]
fn to_binary(self) -> i128 {
self.0 as _
}
#[inline]
fn from_binary(bits: i128) -> Self {
// TODO: ensure that the safety invariants are actually upheld here
Self(bits as _)
}
}
impl VMFuncRef {
/// Check if the FuncRef is null
// TODO: make this const when `std::ptr::is_null` is const
pub fn is_null(&self) -> bool {
self.0.is_null()
}
/// Create a new null FuncRef
pub const fn null() -> Self {
Self(std::ptr::null())
}
}
impl std::ops::Deref for VMFuncRef {
type Target = *const VMCallerCheckedAnyfunc;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for VMFuncRef {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
// We use raw pointers but the data never moves, so it's not a problem
// TODO: update docs
unsafe impl Send for VMFuncRef {}
unsafe impl Sync for VMFuncRef {}
#[derive(Debug, Default, MemoryUsage)]
struct Inner {
func_data: Vec<Box<VMCallerCheckedAnyfunc>>,
anyfunc_to_index: HashMap<VMCallerCheckedAnyfunc, usize>,
}
impl FuncDataRegistry {
/// Create a new `FuncDataRegistry`.
pub fn new() -> Self {
Self {
inner: Default::default(),
}
}
/// Register a signature and return its unique index.
pub fn register(&self, anyfunc: VMCallerCheckedAnyfunc) -> VMFuncRef {
let mut inner = self.inner.lock().unwrap();
if let Some(&idx) = inner.anyfunc_to_index.get(&anyfunc) {
let data: &Box<_> = &inner.func_data[idx];
let inner_ptr: &VMCallerCheckedAnyfunc = &*data;
VMFuncRef(inner_ptr)
} else {
let idx = inner.func_data.len();
inner.func_data.push(Box::new(anyfunc.clone()));
inner.anyfunc_to_index.insert(anyfunc, idx);
let data: &Box<_> = &inner.func_data[idx];
let inner_ptr: &VMCallerCheckedAnyfunc = &*data;
VMFuncRef(inner_ptr)
}
}
}

View File

@@ -4,7 +4,7 @@ use std::cell::UnsafeCell;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::Mutex; use std::sync::Mutex;
use thiserror::Error; use thiserror::Error;
use wasmer_types::{GlobalType, Mutability, Type, Value}; use wasmer_types::{GlobalType, Mutability, Type, Value, WasmValueType};
#[derive(Debug, MemoryUsage)] #[derive(Debug, MemoryUsage)]
/// A Global instance /// A Global instance
@@ -65,7 +65,10 @@ impl Global {
} }
/// Get a value from the global. /// Get a value from the global.
pub fn get<T>(&self) -> Value<T> { // TODO(reftypes): the `&dyn Any` here for `Store` is a work-around for the fact
// that `Store` is defined in `API` when we need it earlier. Ideally this should
// be removed.
pub fn get<T: WasmValueType>(&self, store: &dyn std::any::Any) -> Value<T> {
let _global_guard = self.lock.lock().unwrap(); let _global_guard = self.lock.lock().unwrap();
unsafe { unsafe {
let definition = &*self.vm_global_definition.get(); let definition = &*self.vm_global_definition.get();
@@ -75,7 +78,16 @@ impl Global {
Type::F32 => Value::F32(definition.to_f32()), Type::F32 => Value::F32(definition.to_f32()),
Type::F64 => Value::F64(definition.to_f64()), Type::F64 => Value::F64(definition.to_f64()),
Type::V128 => Value::V128(definition.to_u128()), Type::V128 => Value::V128(definition.to_u128()),
_ => unimplemented!("Global::get for {:?}", self.ty), Type::ExternRef => Value::ExternRef(definition.to_externref().into()),
Type::FuncRef => {
let p = definition.to_u128() as i128;
if p as usize == 0 {
Value::FuncRef(None)
} else {
let v = T::read_value_from(store, &p);
Value::FuncRef(Some(v))
}
}
} }
} }
} }
@@ -84,7 +96,7 @@ impl Global {
/// ///
/// # Safety /// # Safety
/// The caller should check that the `val` comes from the same store as this global. /// The caller should check that the `val` comes from the same store as this global.
pub unsafe fn set<T>(&self, val: Value<T>) -> Result<(), GlobalError> { pub unsafe fn set<T: WasmValueType>(&self, val: Value<T>) -> Result<(), GlobalError> {
let _global_guard = self.lock.lock().unwrap(); let _global_guard = self.lock.lock().unwrap();
if self.ty().mutability != Mutability::Var { if self.ty().mutability != Mutability::Var {
return Err(GlobalError::ImmutableGlobalCannotBeSet); return Err(GlobalError::ImmutableGlobalCannotBeSet);
@@ -104,7 +116,7 @@ impl Global {
/// The caller should check that the `val` comes from the same store as this global. /// The caller should check that the `val` comes from the same store as this global.
/// The caller should also ensure that this global is synchronized. Otherwise, use /// The caller should also ensure that this global is synchronized. Otherwise, use
/// `set` instead. /// `set` instead.
pub unsafe fn set_unchecked<T>(&self, val: Value<T>) -> Result<(), GlobalError> { pub unsafe fn set_unchecked<T: WasmValueType>(&self, val: Value<T>) -> Result<(), GlobalError> {
// ideally we'd use atomics for the global value rather than needing to lock it // ideally we'd use atomics for the global value rather than needing to lock it
let definition = &mut *self.vm_global_definition.get(); let definition = &mut *self.vm_global_definition.get();
match val { match val {
@@ -113,7 +125,15 @@ impl Global {
Value::F32(f) => *definition.as_f32_mut() = f, Value::F32(f) => *definition.as_f32_mut() = f,
Value::F64(f) => *definition.as_f64_mut() = f, Value::F64(f) => *definition.as_f64_mut() = f,
Value::V128(x) => *definition.as_bytes_mut() = x.to_ne_bytes(), Value::V128(x) => *definition.as_bytes_mut() = x.to_ne_bytes(),
_ => unimplemented!("Global::set for {:?}", val.ty()), Value::ExternRef(r) => {
let extern_ref = definition.as_externref_mut();
extern_ref.ref_drop();
*extern_ref = r.into()
}
Value::FuncRef(None) => *definition.as_u128_mut() = 0,
Value::FuncRef(Some(r)) => {
r.write_value_to(definition.as_u128_mut() as *mut u128 as *mut i128)
}
} }
Ok(()) Ok(())
} }

View File

@@ -14,10 +14,11 @@ pub use allocator::InstanceAllocator;
pub use r#ref::InstanceRef; pub use r#ref::InstanceRef;
use crate::export::VMExport; use crate::export::VMExport;
use crate::func_data_registry::{FuncDataRegistry, VMFuncRef};
use crate::global::Global; use crate::global::Global;
use crate::imports::Imports; use crate::imports::Imports;
use crate::memory::{Memory, MemoryError}; use crate::memory::{Memory, MemoryError};
use crate::table::Table; use crate::table::{Table, TableElement};
use crate::trap::{catch_traps, init_traps, Trap, TrapCode}; use crate::trap::{catch_traps, init_traps, Trap, TrapCode};
use crate::vmcontext::{ use crate::vmcontext::{
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody,
@@ -32,6 +33,7 @@ use memoffset::offset_of;
use more_asserts::assert_lt; use more_asserts::assert_lt;
use std::any::Any; use std::any::Any;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use std::ffi; use std::ffi;
use std::fmt; use std::fmt;
@@ -84,11 +86,14 @@ pub(crate) struct Instance {
/// Passive elements in this instantiation. As `elem.drop`s happen, these /// Passive elements in this instantiation. As `elem.drop`s happen, these
/// entries get removed. /// entries get removed.
passive_elements: RefCell<PrimaryMap<ElemIndex, Option<Box<[VMCallerCheckedAnyfunc]>>>>, passive_elements: RefCell<HashMap<ElemIndex, Box<[VMFuncRef]>>>,
/// Passive data segments from our module. As `data.drop`s happen, entries /// Passive data segments from our module. As `data.drop`s happen, entries
/// get removed. A missing entry is considered equivalent to an empty slice. /// get removed. A missing entry is considered equivalent to an empty slice.
passive_data: RefCell<PrimaryMap<DataIndex, Option<Arc<[u8]>>>>, passive_data: RefCell<HashMap<DataIndex, Arc<[u8]>>>,
/// mapping of function indices to their func ref backing data.
funcrefs: BoxedSlice<FunctionIndex, VMFuncRef>,
/// Hosts can store arbitrary per-instance information here. /// Hosts can store arbitrary per-instance information here.
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
@@ -216,17 +221,11 @@ impl Instance {
.cast() .cast()
} }
/// Return the indexed `VMSharedSignatureIndex`.
fn signature_id(&self, index: SignatureIndex) -> VMSharedSignatureIndex {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { *self.signature_ids_ptr().add(index) }
}
fn module(&self) -> &Arc<ModuleInfo> { fn module(&self) -> &Arc<ModuleInfo> {
&self.module &self.module
} }
fn module_ref(&self) -> &ModuleInfo { pub(crate) fn module_ref(&self) -> &ModuleInfo {
&*self.module &*self.module
} }
@@ -524,38 +523,90 @@ impl Instance {
from.size() from.size()
} }
/// Returns the number of elements in a given table.
pub(crate) fn table_size(&self, table_index: LocalTableIndex) -> u32 {
self.tables
.get(table_index)
.unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
.size()
}
/// Returns the number of elements in a given imported table.
///
/// # Safety
/// `table_index` must be a valid, imported table index.
pub(crate) unsafe fn imported_table_size(&self, table_index: TableIndex) -> u32 {
let import = self.imported_table(table_index);
let from = import.from.as_ref();
from.size()
}
/// Grow table by the specified amount of elements. /// Grow table by the specified amount of elements.
/// ///
/// Returns `None` if table can't be grown by the specified amount /// Returns `None` if table can't be grown by the specified amount
/// of elements. /// of elements.
pub(crate) fn table_grow(&self, table_index: LocalTableIndex, delta: u32) -> Option<u32> { pub(crate) fn table_grow(
&self,
table_index: LocalTableIndex,
delta: u32,
init_value: TableElement,
) -> Option<u32> {
let result = self let result = self
.tables .tables
.get(table_index) .get(table_index)
.unwrap_or_else(|| panic!("no table for index {}", table_index.index())) .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
.grow(delta); .grow(delta, init_value);
result result
} }
/// Grow table by the specified amount of elements.
///
/// # Safety
/// `table_index` must be a valid, imported table index.
pub(crate) unsafe fn imported_table_grow(
&self,
table_index: TableIndex,
delta: u32,
init_value: TableElement,
) -> Option<u32> {
let import = self.imported_table(table_index);
let from = import.from.as_ref();
from.grow(delta.into(), init_value)
}
/// Get table element by index. /// Get table element by index.
fn table_get( pub(crate) fn table_get(
&self, &self,
table_index: LocalTableIndex, table_index: LocalTableIndex,
index: u32, index: u32,
) -> Option<VMCallerCheckedAnyfunc> { ) -> Option<TableElement> {
self.tables self.tables
.get(table_index) .get(table_index)
.unwrap_or_else(|| panic!("no table for index {}", table_index.index())) .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
.get(index) .get(index)
} }
/// Returns the element at the given index.
///
/// # Safety
/// `table_index` must be a valid, imported table index.
pub(crate) unsafe fn imported_table_get(
&self,
table_index: TableIndex,
index: u32,
) -> Option<TableElement> {
let import = self.imported_table(table_index);
let from = import.from.as_ref();
from.get(index)
}
/// Set table element by index. /// Set table element by index.
fn table_set( pub(crate) fn table_set(
&self, &self,
table_index: LocalTableIndex, table_index: LocalTableIndex,
index: u32, index: u32,
val: VMCallerCheckedAnyfunc, val: TableElement,
) -> Result<(), Trap> { ) -> Result<(), Trap> {
self.tables self.tables
.get(table_index) .get(table_index)
@@ -563,32 +614,31 @@ impl Instance {
.set(index, val) .set(index, val)
} }
/// Get a `VMCallerCheckedAnyfunc` for the given `FunctionIndex`. /// Set table element by index for an imported table.
fn get_caller_checked_anyfunc(&self, index: FunctionIndex) -> VMCallerCheckedAnyfunc { ///
/// # Safety
/// `table_index` must be a valid, imported table index.
pub(crate) unsafe fn imported_table_set(
&self,
table_index: TableIndex,
index: u32,
val: TableElement,
) -> Result<(), Trap> {
let import = self.imported_table(table_index);
let from = import.from.as_ref();
from.set(index, val)
}
pub(crate) fn func_ref(&self, function_index: FunctionIndex) -> Option<VMFuncRef> {
Some(self.get_vm_funcref(function_index))
}
/// Get a `VMFuncRef` for the given `FunctionIndex`.
fn get_vm_funcref(&self, index: FunctionIndex) -> VMFuncRef {
if index == FunctionIndex::reserved_value() { if index == FunctionIndex::reserved_value() {
return VMCallerCheckedAnyfunc::default(); return VMFuncRef::null();
}
let sig = self.module.functions[index];
let type_index = self.signature_id(sig);
let (func_ptr, vmctx) = if let Some(def_index) = self.module.local_func_index(index) {
(
self.functions[def_index].0 as *const _,
VMFunctionEnvironment {
vmctx: self.vmctx_ptr(),
},
)
} else {
let import = self.imported_function(index);
(import.body, import.environment)
};
VMCallerCheckedAnyfunc {
func_ptr,
type_index,
vmctx,
} }
self.funcrefs[index]
} }
/// The `table.init` operation: initializes a portion of a table with a /// The `table.init` operation: initializes a portion of a table with a
@@ -611,9 +661,8 @@ impl Instance {
let table = self.get_table(table_index); let table = self.get_table(table_index);
let passive_elements = self.passive_elements.borrow(); let passive_elements = self.passive_elements.borrow();
let elem = passive_elements let elem = passive_elements
.get(elem_index) .get(&elem_index)
.and_then(|e| e.as_ref().map(|e| &**e)) .map_or::<&[VMFuncRef], _>(&[], |e| &**e);
.unwrap_or(&[]);
if src if src
.checked_add(len) .checked_add(len)
@@ -625,7 +674,40 @@ impl Instance {
for (dst, src) in (dst..dst + len).zip(src..src + len) { for (dst, src) in (dst..dst + len).zip(src..src + len) {
table table
.set(dst, elem[src as usize].clone()) .set(dst, TableElement::FuncRef(elem[src as usize]))
.expect("should never panic because we already did the bounds check above");
}
Ok(())
}
/// The `table.fill` operation: fills a portion of a table with a given value.
///
/// # Errors
///
/// Returns a `Trap` error when the range within the table is out of bounds
pub(crate) fn table_fill(
&self,
table_index: TableIndex,
start_index: u32,
item: TableElement,
len: u32,
) -> Result<(), Trap> {
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
let table = self.get_table(table_index);
let table_size = table.size() as usize;
if start_index
.checked_add(len)
.map_or(true, |n| n as usize > table_size)
{
return Err(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds));
}
for i in start_index..(start_index + len) {
table
.set(i, item.clone())
.expect("should never panic because we already did the bounds check above"); .expect("should never panic because we already did the bounds check above");
} }
@@ -637,7 +719,7 @@ impl Instance {
// https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop
let mut passive_elements = self.passive_elements.borrow_mut(); let mut passive_elements = self.passive_elements.borrow_mut();
passive_elements[elem_index] = None; passive_elements.remove(&elem_index);
// Note that we don't check that we actually removed an element because // Note that we don't check that we actually removed an element because
// dropping a non-passive element is a no-op (not a trap). // dropping a non-passive element is a no-op (not a trap).
} }
@@ -730,10 +812,7 @@ impl Instance {
let memory = self.get_memory(memory_index); let memory = self.get_memory(memory_index);
let passive_data = self.passive_data.borrow(); let passive_data = self.passive_data.borrow();
let data = passive_data let data = passive_data.get(&data_index).map_or(&[][..], |d| &**d);
.get(data_index)
.and_then(|data| data.as_ref().map(|d| &**d))
.unwrap_or(&[][..]);
if src if src
.checked_add(len) .checked_add(len)
@@ -759,7 +838,7 @@ impl Instance {
/// Drop the given data segment, truncating its length to zero. /// Drop the given data segment, truncating its length to zero.
pub(crate) fn data_drop(&self, data_index: DataIndex) { pub(crate) fn data_drop(&self, data_index: DataIndex) {
let mut passive_data = self.passive_data.borrow_mut(); let mut passive_data = self.passive_data.borrow_mut();
passive_data[data_index] = None; passive_data.remove(&data_index);
} }
/// Get a table by index regardless of whether it is locally-defined or an /// Get a table by index regardless of whether it is locally-defined or an
@@ -828,6 +907,7 @@ impl InstanceHandle {
finished_globals: BoxedSlice<LocalGlobalIndex, Arc<Global>>, finished_globals: BoxedSlice<LocalGlobalIndex, Arc<Global>>,
imports: Imports, imports: Imports,
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>, vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
func_data_registry: &FuncDataRegistry,
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
imported_function_envs: BoxedSlice<FunctionIndex, ImportFunctionEnv>, imported_function_envs: BoxedSlice<FunctionIndex, ImportFunctionEnv>,
) -> Result<Self, Trap> { ) -> Result<Self, Trap> {
@@ -836,16 +916,12 @@ impl InstanceHandle {
.map(|m| m.vmglobal()) .map(|m| m.vmglobal())
.collect::<PrimaryMap<LocalGlobalIndex, _>>() .collect::<PrimaryMap<LocalGlobalIndex, _>>()
.into_boxed_slice(); .into_boxed_slice();
let passive_data = RefCell::new( let passive_data = RefCell::new(module.passive_data.clone());
module
.passive_data
.values()
.map(|data| Some(data.clone()))
.collect(),
);
let handle = { let handle = {
let offsets = allocator.offsets().clone(); let offsets = allocator.offsets().clone();
// use dummy value to create an instance so we can get the vmctx pointer
let funcrefs = PrimaryMap::new().into_boxed_slice();
// Create the `Instance`. The unique, the One. // Create the `Instance`. The unique, the One.
let instance = Instance { let instance = Instance {
module, module,
@@ -858,12 +934,27 @@ impl InstanceHandle {
passive_elements: Default::default(), passive_elements: Default::default(),
passive_data, passive_data,
host_state, host_state,
funcrefs,
signal_handler: Cell::new(None), signal_handler: Cell::new(None),
imported_function_envs, imported_function_envs,
vmctx: VMContext {}, vmctx: VMContext {},
}; };
let instance_ref = allocator.write_instance(instance); let mut instance_ref = allocator.write_instance(instance);
// Set the funcrefs after we've built the instance
{
let instance = instance_ref.as_mut();
let vmctx_ptr = instance.vmctx_ptr();
instance.funcrefs = build_funcrefs(
&*instance.module,
&imports,
&instance.functions,
func_data_registry,
&vmshared_signatures,
vmctx_ptr,
);
}
Self { Self {
instance: instance_ref, instance: instance_ref,
@@ -1109,18 +1200,21 @@ impl InstanceHandle {
/// ///
/// Returns `None` if memory can't be grown by the specified amount /// Returns `None` if memory can't be grown by the specified amount
/// of pages. /// of pages.
pub fn table_grow(&self, table_index: LocalTableIndex, delta: u32) -> Option<u32> { pub fn table_grow(
self.instance().as_ref().table_grow(table_index, delta) &self,
table_index: LocalTableIndex,
delta: u32,
init_value: TableElement,
) -> Option<u32> {
self.instance()
.as_ref()
.table_grow(table_index, delta, init_value)
} }
/// Get table element reference. /// Get table element reference.
/// ///
/// Returns `None` if index is out of bounds. /// Returns `None` if index is out of bounds.
pub fn table_get( pub fn table_get(&self, table_index: LocalTableIndex, index: u32) -> Option<TableElement> {
&self,
table_index: LocalTableIndex,
index: u32,
) -> Option<VMCallerCheckedAnyfunc> {
self.instance().as_ref().table_get(table_index, index) self.instance().as_ref().table_get(table_index, index)
} }
@@ -1131,7 +1225,7 @@ impl InstanceHandle {
&self, &self,
table_index: LocalTableIndex, table_index: LocalTableIndex,
index: u32, index: u32,
val: VMCallerCheckedAnyfunc, val: TableElement,
) -> Result<(), Trap> { ) -> Result<(), Trap> {
self.instance().as_ref().table_set(table_index, index, val) self.instance().as_ref().table_set(table_index, index, val)
} }
@@ -1307,9 +1401,12 @@ fn initialize_tables(instance: &Instance) -> Result<(), Trap> {
} }
for (i, func_idx) in init.elements.iter().enumerate() { for (i, func_idx) in init.elements.iter().enumerate() {
let anyfunc = instance.get_caller_checked_anyfunc(*func_idx); let anyfunc = instance.get_vm_funcref(*func_idx);
table table
.set(u32::try_from(start + i).unwrap(), anyfunc) .set(
u32::try_from(start + i).unwrap(),
TableElement::FuncRef(anyfunc),
)
.unwrap(); .unwrap();
} }
} }
@@ -1327,20 +1424,22 @@ fn initialize_passive_elements(instance: &Instance) {
"should only be called once, at initialization time" "should only be called once, at initialization time"
); );
for (segments, passive_element) in instance passive_elements.extend(
.module instance
.passive_elements .module
.values() .passive_elements
.zip(passive_elements.values_mut())
{
if segments.is_empty() {
continue;
}
*passive_element = segments
.iter() .iter()
.map(|s| Some(instance.get_caller_checked_anyfunc(*s))) .filter(|(_, segments)| !segments.is_empty())
.collect(); .map(|(idx, segments)| {
} (
*idx,
segments
.iter()
.map(|s| instance.get_vm_funcref(*s))
.collect(),
)
}),
);
} }
/// Initialize the table memory from the provided initializers. /// Initialize the table memory from the provided initializers.
@@ -1390,8 +1489,54 @@ fn initialize_globals(instance: &Instance) {
}; };
*to = from; *to = from;
} }
GlobalInit::RefNullConst | GlobalInit::RefFunc(_) => unimplemented!(), GlobalInit::RefNullConst => *(*to).as_funcref_mut() = VMFuncRef::null(),
GlobalInit::RefFunc(func_idx) => {
let funcref = instance.func_ref(*func_idx).unwrap();
*(*to).as_funcref_mut() = funcref;
}
} }
} }
} }
} }
/// Eagerly builds all the `VMFuncRef`s for imported and local functions so that all
/// future funcref operations are just looking up this data.
fn build_funcrefs(
module_info: &ModuleInfo,
imports: &Imports,
finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
func_data_registry: &FuncDataRegistry,
vmshared_signatures: &BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
vmctx_ptr: *mut VMContext,
) -> BoxedSlice<FunctionIndex, VMFuncRef> {
let mut func_refs = PrimaryMap::with_capacity(module_info.functions.len());
// do imported functions
for (index, import) in imports.functions.iter() {
let sig_index = module_info.functions[index];
let type_index = vmshared_signatures[sig_index];
let anyfunc = VMCallerCheckedAnyfunc {
func_ptr: import.body,
type_index,
vmctx: import.environment,
};
let func_ref = func_data_registry.register(anyfunc);
func_refs.push(func_ref);
}
// do local functions
for (local_index, func_ptr) in finished_functions.iter() {
let index = module_info.func_index(local_index);
let sig_index = module_info.functions[index];
let type_index = vmshared_signatures[sig_index];
let anyfunc = VMCallerCheckedAnyfunc {
func_ptr: func_ptr.0,
type_index,
vmctx: VMFunctionEnvironment { vmctx: vmctx_ptr },
};
let func_ref = func_data_registry.register(anyfunc);
func_refs.push(func_ref);
}
func_refs.into_boxed_slice()
}

View File

@@ -21,6 +21,7 @@
)] )]
mod export; mod export;
mod func_data_registry;
mod global; mod global;
mod imports; mod imports;
mod instance; mod instance;
@@ -37,6 +38,7 @@ mod vmoffsets;
pub mod libcalls; pub mod libcalls;
pub use crate::export::*; pub use crate::export::*;
pub use crate::func_data_registry::{FuncDataRegistry, VMFuncRef};
pub use crate::global::*; pub use crate::global::*;
pub use crate::imports::Imports; pub use crate::imports::Imports;
pub use crate::instance::{ pub use crate::instance::{
@@ -47,7 +49,7 @@ pub use crate::mmap::Mmap;
pub use crate::module::{ExportsIterator, ImportsIterator, ModuleInfo}; pub use crate::module::{ExportsIterator, ImportsIterator, ModuleInfo};
pub use crate::probestack::PROBESTACK; pub use crate::probestack::PROBESTACK;
pub use crate::sig_registry::SignatureRegistry; pub use crate::sig_registry::SignatureRegistry;
pub use crate::table::{LinearTable, Table, TableStyle}; pub use crate::table::{LinearTable, Table, TableElement, TableStyle};
pub use crate::trap::*; pub use crate::trap::*;
pub use crate::vmcontext::{ pub use crate::vmcontext::{
VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext,
@@ -57,6 +59,7 @@ pub use crate::vmcontext::{
}; };
pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets}; pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets};
use loupe::MemoryUsage; use loupe::MemoryUsage;
pub use wasmer_types::VMExternRef;
/// Version number of this crate. /// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -35,36 +35,42 @@
//! } //! }
//! ``` //! ```
use crate::func_data_registry::VMFuncRef;
use crate::probestack::PROBESTACK; use crate::probestack::PROBESTACK;
use crate::table::{RawTableElement, TableElement};
use crate::trap::{raise_lib_trap, Trap, TrapCode}; use crate::trap::{raise_lib_trap, Trap, TrapCode};
use crate::vmcontext::VMContext; use crate::vmcontext::VMContext;
use crate::VMExternRef;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
use wasmer_types::{DataIndex, ElemIndex, LocalMemoryIndex, MemoryIndex, TableIndex}; use wasmer_types::{
DataIndex, ElemIndex, FunctionIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
TableIndex, Type,
};
/// Implementation of f32.ceil /// Implementation of f32.ceil
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f32_ceil(x: f32) -> f32 { pub extern "C" fn wasmer_vm_f32_ceil(x: f32) -> f32 {
x.ceil() x.ceil()
} }
/// Implementation of f32.floor /// Implementation of f32.floor
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f32_floor(x: f32) -> f32 { pub extern "C" fn wasmer_vm_f32_floor(x: f32) -> f32 {
x.floor() x.floor()
} }
/// Implementation of f32.trunc /// Implementation of f32.trunc
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f32_trunc(x: f32) -> f32 { pub extern "C" fn wasmer_vm_f32_trunc(x: f32) -> f32 {
x.trunc() x.trunc()
} }
/// Implementation of f32.nearest /// Implementation of f32.nearest
#[allow(clippy::float_arithmetic, clippy::float_cmp)] #[allow(clippy::float_arithmetic, clippy::float_cmp)]
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f32_nearest(x: f32) -> f32 { pub extern "C" fn wasmer_vm_f32_nearest(x: f32) -> f32 {
// Rust doesn't have a nearest function, so do it manually. // Rust doesn't have a nearest function, so do it manually.
if x == 0.0 { if x == 0.0 {
// Preserve the sign of zero. // Preserve the sign of zero.
@@ -90,26 +96,26 @@ pub extern "C" fn wasmer_f32_nearest(x: f32) -> f32 {
/// Implementation of f64.ceil /// Implementation of f64.ceil
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f64_ceil(x: f64) -> f64 { pub extern "C" fn wasmer_vm_f64_ceil(x: f64) -> f64 {
x.ceil() x.ceil()
} }
/// Implementation of f64.floor /// Implementation of f64.floor
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f64_floor(x: f64) -> f64 { pub extern "C" fn wasmer_vm_f64_floor(x: f64) -> f64 {
x.floor() x.floor()
} }
/// Implementation of f64.trunc /// Implementation of f64.trunc
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f64_trunc(x: f64) -> f64 { pub extern "C" fn wasmer_vm_f64_trunc(x: f64) -> f64 {
x.trunc() x.trunc()
} }
/// Implementation of f64.nearest /// Implementation of f64.nearest
#[allow(clippy::float_arithmetic, clippy::float_cmp)] #[allow(clippy::float_arithmetic, clippy::float_cmp)]
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_f64_nearest(x: f64) -> f64 { pub extern "C" fn wasmer_vm_f64_nearest(x: f64) -> f64 {
// Rust doesn't have a nearest function, so do it manually. // Rust doesn't have a nearest function, so do it manually.
if x == 0.0 { if x == 0.0 {
// Preserve the sign of zero. // Preserve the sign of zero.
@@ -137,8 +143,9 @@ pub extern "C" fn wasmer_f64_nearest(x: f64) -> f64 {
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_memory32_grow( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_memory32_grow(
vmctx: *mut VMContext, vmctx: *mut VMContext,
delta: u32, delta: u32,
memory_index: u32, memory_index: u32,
@@ -156,8 +163,9 @@ pub unsafe extern "C" fn wasmer_memory32_grow(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_imported_memory32_grow( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_memory32_grow(
vmctx: *mut VMContext, vmctx: *mut VMContext,
delta: u32, delta: u32,
memory_index: u32, memory_index: u32,
@@ -175,8 +183,9 @@ pub unsafe extern "C" fn wasmer_imported_memory32_grow(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 { #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
let instance = (&*vmctx).instance(); let instance = (&*vmctx).instance();
let memory_index = LocalMemoryIndex::from_u32(memory_index); let memory_index = LocalMemoryIndex::from_u32(memory_index);
@@ -187,8 +196,9 @@ pub unsafe extern "C" fn wasmer_memory32_size(vmctx: *mut VMContext, memory_inde
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_imported_memory32_size( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_memory32_size(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
) -> u32 { ) -> u32 {
@@ -202,8 +212,9 @@ pub unsafe extern "C" fn wasmer_imported_memory32_size(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_table_copy( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_copy(
vmctx: *mut VMContext, vmctx: *mut VMContext,
dst_table_index: u32, dst_table_index: u32,
src_table_index: u32, src_table_index: u32,
@@ -228,8 +239,9 @@ pub unsafe extern "C" fn wasmer_table_copy(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_table_init( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_init(
vmctx: *mut VMContext, vmctx: *mut VMContext,
table_index: u32, table_index: u32,
elem_index: u32, elem_index: u32,
@@ -248,12 +260,268 @@ pub unsafe extern "C" fn wasmer_table_init(
} }
} }
/// Implementation of `table.fill`.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_fill(
vmctx: *mut VMContext,
table_index: u32,
start_idx: u32,
item: RawTableElement,
len: u32,
) {
let result = {
let table_index = TableIndex::from_u32(table_index);
let instance = (&*vmctx).instance();
let elem = match instance.get_table(table_index).ty().ty {
Type::ExternRef => TableElement::ExternRef(item.extern_ref.into()),
Type::FuncRef => TableElement::FuncRef(item.func_ref),
_ => panic!("Unrecognized table type: does not contain references"),
};
instance.table_fill(table_index, start_idx, elem, len)
};
if let Err(trap) = result {
raise_lib_trap(trap);
}
}
/// Implementation of `table.size`.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 {
let instance = (&*vmctx).instance();
let table_index = LocalTableIndex::from_u32(table_index);
instance.table_size(table_index)
}
/// Implementation of `table.size` for imported tables.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_table_size(
vmctx: *mut VMContext,
table_index: u32,
) -> u32 {
let instance = (&*vmctx).instance();
let table_index = TableIndex::from_u32(table_index);
instance.imported_table_size(table_index)
}
/// Implementation of `table.get`.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_get(
vmctx: *mut VMContext,
table_index: u32,
elem_index: u32,
) -> RawTableElement {
let instance = (&*vmctx).instance();
let table_index = LocalTableIndex::from_u32(table_index);
// TODO: type checking, maybe have specialized accessors
match instance.table_get(table_index, elem_index) {
Some(table_ref) => table_ref.into(),
None => raise_lib_trap(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds)),
}
}
/// Implementation of `table.get` for imported tables.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_table_get(
vmctx: *mut VMContext,
table_index: u32,
elem_index: u32,
) -> RawTableElement {
let instance = (&*vmctx).instance();
let table_index = TableIndex::from_u32(table_index);
// TODO: type checking, maybe have specialized accessors
match instance.imported_table_get(table_index, elem_index) {
Some(table_ref) => table_ref.into(),
None => raise_lib_trap(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds)),
}
}
/// Implementation of `table.set`.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
///
/// It is the caller's responsibility to increment the ref count of any ref counted
/// type before passing it to this function.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_set(
vmctx: *mut VMContext,
table_index: u32,
elem_index: u32,
value: RawTableElement,
) {
let instance = (&*vmctx).instance();
let table_index = TableIndex::from_u32(table_index);
let table_index = instance
.module_ref()
.local_table_index(table_index)
.unwrap();
let elem = match instance.get_local_table(table_index).ty().ty {
Type::ExternRef => TableElement::ExternRef(value.extern_ref.into()),
Type::FuncRef => TableElement::FuncRef(value.func_ref),
_ => panic!("Unrecognized table type: does not contain references"),
};
// TODO: type checking, maybe have specialized accessors
let result = instance.table_set(table_index, elem_index, elem);
if let Err(trap) = result {
raise_lib_trap(trap);
}
}
/// Implementation of `table.set` for imported tables.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_table_set(
vmctx: *mut VMContext,
table_index: u32,
elem_index: u32,
value: RawTableElement,
) {
let instance = (&*vmctx).instance();
let table_index = TableIndex::from_u32(table_index);
let elem = match instance.get_table(table_index).ty().ty {
Type::ExternRef => TableElement::ExternRef(value.extern_ref.into()),
Type::FuncRef => TableElement::FuncRef(value.func_ref),
_ => panic!("Unrecognized table type: does not contain references"),
};
let result = instance.imported_table_set(table_index, elem_index, elem);
if let Err(trap) = result {
raise_lib_trap(trap);
}
}
/// Implementation of `table.grow` for locally-defined tables.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_grow(
vmctx: *mut VMContext,
init_value: RawTableElement,
delta: u32,
table_index: u32,
) -> u32 {
let instance = (&*vmctx).instance();
let table_index = LocalTableIndex::from_u32(table_index);
let init_value = match instance.get_local_table(table_index).ty().ty {
Type::ExternRef => TableElement::ExternRef(init_value.extern_ref.into()),
Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
_ => panic!("Unrecognized table type: does not contain references"),
};
instance
.table_grow(table_index, delta, init_value)
.unwrap_or(u32::max_value())
}
/// Implementation of `table.grow` for imported tables.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_table_grow(
vmctx: *mut VMContext,
init_value: RawTableElement,
delta: u32,
table_index: u32,
) -> u32 {
let instance = (&*vmctx).instance();
let table_index = TableIndex::from_u32(table_index);
let init_value = match instance.get_table(table_index).ty().ty {
Type::ExternRef => TableElement::ExternRef(init_value.extern_ref.into()),
Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
_ => panic!("Unrecognized table type: does not contain references"),
};
instance
.imported_table_grow(table_index, delta, init_value)
.unwrap_or(u32::max_value())
}
/// Implementation of `func.ref`.
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_func_ref(
vmctx: *mut VMContext,
function_index: u32,
) -> VMFuncRef {
let instance = (&*vmctx).instance();
let function_index = FunctionIndex::from_u32(function_index);
instance.func_ref(function_index).unwrap()
}
/// Implementation of externref increment
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
///
/// This function must only be called at precise locations to prevent memory leaks.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_externref_inc(externref: VMExternRef) {
externref.ref_clone();
}
/// Implementation of externref decrement
///
/// # Safety
///
/// `vmctx` must be dereferenceable.
///
/// This function must only be called at precise locations, otherwise use-after-free
/// and other serious memory bugs may occur.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_externref_dec(mut externref: VMExternRef) {
externref.ref_drop()
}
/// Implementation of `elem.drop`. /// Implementation of `elem.drop`.
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_elem_drop(vmctx: *mut VMContext, elem_index: u32) { #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
let elem_index = ElemIndex::from_u32(elem_index); let elem_index = ElemIndex::from_u32(elem_index);
let instance = (&*vmctx).instance(); let instance = (&*vmctx).instance();
instance.elem_drop(elem_index); instance.elem_drop(elem_index);
@@ -263,8 +531,9 @@ pub unsafe extern "C" fn wasmer_elem_drop(vmctx: *mut VMContext, elem_index: u32
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_local_memory_copy( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_memory32_copy(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
dst: u32, dst: u32,
@@ -285,8 +554,9 @@ pub unsafe extern "C" fn wasmer_local_memory_copy(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_imported_memory_copy( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_memory32_copy(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
dst: u32, dst: u32,
@@ -307,8 +577,9 @@ pub unsafe extern "C" fn wasmer_imported_memory_copy(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_memory_fill( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_memory32_fill(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
dst: u32, dst: u32,
@@ -329,8 +600,9 @@ pub unsafe extern "C" fn wasmer_memory_fill(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_imported_memory_fill( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_imported_memory32_fill(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
dst: u32, dst: u32,
@@ -351,8 +623,9 @@ pub unsafe extern "C" fn wasmer_imported_memory_fill(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_memory_init( #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_memory32_init(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
data_index: u32, data_index: u32,
@@ -375,8 +648,9 @@ pub unsafe extern "C" fn wasmer_memory_init(
/// ///
/// # Safety /// # Safety
/// ///
/// `vmctx` must be valid and not null. /// `vmctx` must be dereferenceable.
pub unsafe extern "C" fn wasmer_data_drop(vmctx: *mut VMContext, data_index: u32) { #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index: u32) {
let data_index = DataIndex::from_u32(data_index); let data_index = DataIndex::from_u32(data_index);
let instance = (&*vmctx).instance(); let instance = (&*vmctx).instance();
instance.data_drop(data_index) instance.data_drop(data_index)
@@ -389,7 +663,7 @@ pub unsafe extern "C" fn wasmer_data_drop(vmctx: *mut VMContext, data_index: u32
/// Only safe to call when wasm code is on the stack, aka `wasmer_call` or /// Only safe to call when wasm code is on the stack, aka `wasmer_call` or
/// `wasmer_call_trampoline` must have been previously called. /// `wasmer_call_trampoline` must have been previously called.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasmer_raise_trap(trap_code: TrapCode) -> ! { pub unsafe extern "C" fn wasmer_vm_raise_trap(trap_code: TrapCode) -> ! {
let trap = Trap::new_from_runtime(trap_code); let trap = Trap::new_from_runtime(trap_code);
raise_lib_trap(trap) raise_lib_trap(trap)
} }
@@ -401,7 +675,7 @@ pub unsafe extern "C" fn wasmer_raise_trap(trap_code: TrapCode) -> ! {
/// This function does not follow the standard function ABI, and is called as /// This function does not follow the standard function ABI, and is called as
/// part of the function prologue. /// part of the function prologue.
#[no_mangle] #[no_mangle]
pub static wasmer_probestack: unsafe extern "C" fn() = PROBESTACK; pub static wasmer_vm_probestack: unsafe extern "C" fn() = PROBESTACK;
/// The name of a runtime library routine. /// The name of a runtime library routine.
/// ///
@@ -426,55 +700,160 @@ pub enum LibCall {
/// nearest.f64 /// nearest.f64
NearestF64, NearestF64,
/// probe for stack overflow. These are emitted for functions which need /// trunc.f32
/// when the `enable_probestack` setting is true. TruncF32,
Probestack,
/// trunc.f64
TruncF64,
/// memory.size for local functions
Memory32Size,
/// memory.size for imported functions
ImportedMemory32Size,
/// table.copy
TableCopy,
/// table.init
TableInit,
/// table.fill
TableFill,
/// table.size for local tables
TableSize,
/// table.size for imported tables
ImportedTableSize,
/// table.get for local tables
TableGet,
/// table.get for imported tables
ImportedTableGet,
/// table.set for local tables
TableSet,
/// table.set for imported tables
ImportedTableSet,
/// table.grow for local tables
TableGrow,
/// table.grow for imported tables
ImportedTableGrow,
/// ref.func
FuncRef,
/// elem.drop
ElemDrop,
/// memory.copy for local memories
Memory32Copy,
/// memory.copy for imported memories
ImportedMemory32Copy,
/// memory.fill for local memories
Memory32Fill,
/// memory.fill for imported memories
ImportedMemory32Fill,
/// memory.init
Memory32Init,
/// data.drop
DataDrop,
/// A custom trap /// A custom trap
RaiseTrap, RaiseTrap,
/// trunc.f32 /// probe for stack overflow. These are emitted for functions which need
TruncF32, /// when the `enable_probestack` setting is true.
Probestack,
/// frunc.f64
TruncF64,
} }
impl LibCall { impl LibCall {
/// The function pointer to a libcall /// The function pointer to a libcall
pub fn function_pointer(self) -> usize { pub fn function_pointer(self) -> usize {
match self { match self {
Self::CeilF32 => wasmer_f32_ceil as usize, Self::CeilF32 => wasmer_vm_f32_ceil as usize,
Self::CeilF64 => wasmer_f64_ceil as usize, Self::CeilF64 => wasmer_vm_f64_ceil as usize,
Self::FloorF32 => wasmer_f32_floor as usize, Self::FloorF32 => wasmer_vm_f32_floor as usize,
Self::FloorF64 => wasmer_f64_floor as usize, Self::FloorF64 => wasmer_vm_f64_floor as usize,
Self::NearestF32 => wasmer_f32_nearest as usize, Self::NearestF32 => wasmer_vm_f32_nearest as usize,
Self::NearestF64 => wasmer_f64_nearest as usize, Self::NearestF64 => wasmer_vm_f64_nearest as usize,
Self::Probestack => wasmer_probestack as usize, Self::TruncF32 => wasmer_vm_f32_trunc as usize,
Self::RaiseTrap => wasmer_raise_trap as usize, Self::TruncF64 => wasmer_vm_f64_trunc as usize,
Self::TruncF32 => wasmer_f32_trunc as usize, Self::Memory32Size => wasmer_vm_memory32_size as usize,
Self::TruncF64 => wasmer_f64_trunc as usize, Self::ImportedMemory32Size => wasmer_vm_imported_memory32_size as usize,
Self::TableCopy => wasmer_vm_table_copy as usize,
Self::TableInit => wasmer_vm_table_init as usize,
Self::TableFill => wasmer_vm_table_fill as usize,
Self::TableSize => wasmer_vm_table_size as usize,
Self::ImportedTableSize => wasmer_vm_imported_table_size as usize,
Self::TableGet => wasmer_vm_table_get as usize,
Self::ImportedTableGet => wasmer_vm_imported_table_get as usize,
Self::TableSet => wasmer_vm_table_set as usize,
Self::ImportedTableSet => wasmer_vm_imported_table_set as usize,
Self::TableGrow => wasmer_vm_table_grow as usize,
Self::ImportedTableGrow => wasmer_vm_imported_table_grow as usize,
Self::FuncRef => wasmer_vm_func_ref as usize,
Self::ElemDrop => wasmer_vm_elem_drop as usize,
Self::Memory32Copy => wasmer_vm_memory32_copy as usize,
Self::ImportedMemory32Copy => wasmer_vm_imported_memory32_copy as usize,
Self::Memory32Fill => wasmer_vm_memory32_fill as usize,
Self::ImportedMemory32Fill => wasmer_vm_memory32_fill as usize,
Self::Memory32Init => wasmer_vm_memory32_init as usize,
Self::DataDrop => wasmer_vm_data_drop as usize,
Self::Probestack => wasmer_vm_probestack as usize,
Self::RaiseTrap => wasmer_vm_raise_trap as usize,
} }
} }
/// Return the function name associated to the libcall. /// Return the function name associated to the libcall.
pub fn to_function_name(&self) -> &str { pub fn to_function_name(&self) -> &str {
match self { match self {
Self::CeilF32 => "wasmer_f32_ceil", Self::CeilF32 => "wasmer_vm_f32_ceil",
Self::CeilF64 => "wasmer_f64_ceil", Self::CeilF64 => "wasmer_vm_f64_ceil",
Self::FloorF32 => "wasmer_f32_floor", Self::FloorF32 => "wasmer_vm_f32_floor",
Self::FloorF64 => "wasmer_f64_floor", Self::FloorF64 => "wasmer_vm_f64_floor",
Self::NearestF32 => "wasmer_f32_nearest", Self::NearestF32 => "wasmer_vm_f32_nearest",
Self::NearestF64 => "wasmer_f64_nearest", Self::NearestF64 => "wasmer_vm_f64_nearest",
Self::TruncF32 => "wasmer_vm_f32_trunc",
Self::TruncF64 => "wasmer_vm_f64_trunc",
Self::Memory32Size => "wasmer_vm_memory32_size",
Self::ImportedMemory32Size => "wasmer_vm_imported_memory32_size",
Self::TableCopy => "wasmer_vm_table_copy",
Self::TableInit => "wasmer_vm_table_init",
Self::TableFill => "wasmer_vm_table_fill",
Self::TableSize => "wasmer_vm_table_size",
Self::ImportedTableSize => "wasmer_vm_imported_table_size",
Self::TableGet => "wasmer_vm_table_get",
Self::ImportedTableGet => "wasmer_vm_imported_table_get",
Self::TableSet => "wasmer_vm_table_set",
Self::ImportedTableSet => "wasmer_vm_imported_table_set",
Self::TableGrow => "wasmer_vm_table_grow",
Self::ImportedTableGrow => "wasmer_vm_imported_table_grow",
Self::FuncRef => "wasmer_vm_func_ref",
Self::ElemDrop => "wasmer_vm_elem_drop",
Self::Memory32Copy => "wasmer_vm_memory32_copy",
Self::ImportedMemory32Copy => "wasmer_vm_imported_memory32_copy",
Self::Memory32Fill => "wasmer_vm_memory32_fill",
Self::ImportedMemory32Fill => "wasmer_vm_imported_memory32_fill",
Self::Memory32Init => "wasmer_vm_memory32_init",
Self::DataDrop => "wasmer_vm_data_drop",
Self::RaiseTrap => "wasmer_vm_raise_trap",
// We have to do this because macOS requires a leading `_` and it's not // We have to do this because macOS requires a leading `_` and it's not
// a normal function, it's a static variable, so we have to do it manually. // a normal function, it's a static variable, so we have to do it manually.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
Self::Probestack => "_wasmer_probestack", Self::Probestack => "_wasmer_vm_probestack",
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
Self::Probestack => "wasmer_probestack", Self::Probestack => "wasmer_vm_probestack",
Self::RaiseTrap => "wasmer_raise_trap",
Self::TruncF32 => "wasmer_f32_trunc",
Self::TruncF64 => "wasmer_f64_trunc",
} }
} }
} }

View File

@@ -80,10 +80,10 @@ pub struct ModuleInfo {
pub table_initializers: Vec<TableInitializer>, pub table_initializers: Vec<TableInitializer>,
/// WebAssembly passive elements. /// WebAssembly passive elements.
pub passive_elements: PrimaryMap<ElemIndex, Box<[FunctionIndex]>>, pub passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
/// WebAssembly passive data segments. /// WebAssembly passive data segments.
pub passive_data: PrimaryMap<DataIndex, Arc<[u8]>>, pub passive_data: HashMap<DataIndex, Arc<[u8]>>,
/// WebAssembly global initializers. /// WebAssembly global initializers.
pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>, pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
@@ -134,8 +134,8 @@ pub struct ArchivableModuleInfo {
exports: ArchivableIndexMap<String, ExportIndex>, exports: ArchivableIndexMap<String, ExportIndex>,
start_function: Option<FunctionIndex>, start_function: Option<FunctionIndex>,
table_initializers: Vec<TableInitializer>, table_initializers: Vec<TableInitializer>,
passive_elements: PrimaryMap<ElemIndex, Box<[FunctionIndex]>>, passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
passive_data: PrimaryMap<DataIndex, Arc<[u8]>>, passive_data: HashMap<DataIndex, Arc<[u8]>>,
global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>, global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
function_names: HashMap<FunctionIndex, String>, function_names: HashMap<FunctionIndex, String>,
signatures: PrimaryMap<SignatureIndex, FunctionType>, signatures: PrimaryMap<SignatureIndex, FunctionType>,
@@ -281,8 +281,8 @@ impl ModuleInfo {
exports: IndexMap::new(), exports: IndexMap::new(),
start_function: None, start_function: None,
table_initializers: Vec::new(), table_initializers: Vec::new(),
passive_elements: PrimaryMap::new(), passive_elements: HashMap::new(),
passive_data: PrimaryMap::new(), passive_data: HashMap::new(),
global_initializers: PrimaryMap::new(), global_initializers: PrimaryMap::new(),
function_names: HashMap::new(), function_names: HashMap::new(),
signatures: PrimaryMap::new(), signatures: PrimaryMap::new(),
@@ -301,7 +301,7 @@ impl ModuleInfo {
/// Get the given passive element, if it exists. /// Get the given passive element, if it exists.
pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> { pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
self.passive_elements.get(index).map(|es| &**es) self.passive_elements.get(&index).map(|es| &**es)
} }
/// Get the exported signatures of the module /// Get the exported signatures of the module

View File

@@ -5,11 +5,13 @@
//! //!
//! `Table` is to WebAssembly tables what `LinearMemory` is to WebAssembly linear memories. //! `Table` is to WebAssembly tables what `LinearMemory` is to WebAssembly linear memories.
use crate::func_data_registry::VMFuncRef;
use crate::trap::{Trap, TrapCode}; use crate::trap::{Trap, TrapCode};
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
use loupe::MemoryUsage;
#[cfg(feature = "enable-rkyv")] #[cfg(feature = "enable-rkyv")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
use crate::vmcontext::VMTableDefinition;
use crate::VMExternRef;
use loupe::{MemoryUsage, MemoryUsageTracker};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::borrow::{Borrow, BorrowMut}; use std::borrow::{Borrow, BorrowMut};
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
@@ -17,7 +19,7 @@ use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::Mutex; use std::sync::Mutex;
use wasmer_types::{TableType, Type as ValType}; use wasmer_types::{ExternRef, TableType, Type as ValType};
/// Implementation styles for WebAssembly tables. /// Implementation styles for WebAssembly tables.
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, MemoryUsage)] #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, MemoryUsage)]
@@ -45,19 +47,19 @@ pub trait Table: fmt::Debug + Send + Sync + MemoryUsage {
/// ///
/// Returns `None` if table can't be grown by the specified amount /// Returns `None` if table can't be grown by the specified amount
/// of elements, otherwise returns the previous size of the table. /// of elements, otherwise returns the previous size of the table.
fn grow(&self, delta: u32) -> Option<u32>; fn grow(&self, delta: u32, init_value: TableElement) -> Option<u32>;
/// Get reference to the specified element. /// Get reference to the specified element.
/// ///
/// Returns `None` if the index is out of bounds. /// Returns `None` if the index is out of bounds.
fn get(&self, index: u32) -> Option<VMCallerCheckedAnyfunc>; fn get(&self, index: u32) -> Option<TableElement>;
/// Set reference to the specified element. /// Set reference to the specified element.
/// ///
/// # Errors /// # Errors
/// ///
/// Returns an error if the index is out of bounds. /// Returns an error if the index is out of bounds.
fn set(&self, index: u32, func: VMCallerCheckedAnyfunc) -> Result<(), Trap>; fn set(&self, index: u32, reference: TableElement) -> Result<(), Trap>;
/// Return a `VMTableDefinition` for exposing the table to compiled wasm code. /// Return a `VMTableDefinition` for exposing the table to compiled wasm code.
fn vmtable(&self) -> NonNull<VMTableDefinition>; fn vmtable(&self) -> NonNull<VMTableDefinition>;
@@ -109,11 +111,74 @@ pub trait Table: fmt::Debug + Send + Sync + MemoryUsage {
} }
} }
/// A reference stored in a table. Can be either an externref or a funcref.
#[derive(Debug, Clone)]
pub enum TableElement {
/// Opaque pointer to arbitrary host data.
// Note: we use `ExternRef` instead of `VMExternRef` here to ensure that we don't
// leak by not dec-refing on failure types.
ExternRef(ExternRef),
/// Pointer to function: contains enough information to call it.
FuncRef(VMFuncRef),
}
impl From<TableElement> for RawTableElement {
fn from(other: TableElement) -> Self {
match other {
TableElement::ExternRef(extern_ref) => Self {
extern_ref: extern_ref.into(),
},
TableElement::FuncRef(func_ref) => Self { func_ref },
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union RawTableElement {
pub(crate) extern_ref: VMExternRef,
pub(crate) func_ref: VMFuncRef,
}
#[cfg(test)]
#[test]
fn table_element_size_test() {
use std::mem::size_of;
assert_eq!(size_of::<RawTableElement>(), size_of::<VMExternRef>());
assert_eq!(size_of::<RawTableElement>(), size_of::<VMFuncRef>());
}
impl MemoryUsage for RawTableElement {
fn size_of_val(&self, _: &mut dyn MemoryUsageTracker) -> usize {
std::mem::size_of_val(self)
}
}
impl fmt::Debug for RawTableElement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RawTableElement").finish()
}
}
impl Default for RawTableElement {
fn default() -> Self {
Self {
func_ref: VMFuncRef::null(),
}
}
}
impl Default for TableElement {
fn default() -> Self {
Self::FuncRef(VMFuncRef::null())
}
}
/// A table instance. /// A table instance.
#[derive(Debug, MemoryUsage)] #[derive(Debug, MemoryUsage)]
pub struct LinearTable { pub struct LinearTable {
// TODO: we can remove the mutex by using atomic swaps and preallocating the max table size // TODO: we can remove the mutex by using atomic swaps and preallocating the max table size
vec: Mutex<Vec<VMCallerCheckedAnyfunc>>, vec: Mutex<Vec<RawTableElement>>,
maximum: Option<u32>, maximum: Option<u32>,
/// The WebAssembly table description. /// The WebAssembly table description.
table: TableType, table: TableType,
@@ -171,8 +236,13 @@ impl LinearTable {
vm_table_location: Option<NonNull<VMTableDefinition>>, vm_table_location: Option<NonNull<VMTableDefinition>>,
) -> Result<Self, String> { ) -> Result<Self, String> {
match table.ty { match table.ty {
ValType::FuncRef => (), ValType::FuncRef | ValType::ExternRef => (),
ty => return Err(format!("tables of types other than anyfunc ({})", ty)), ty => {
return Err(format!(
"tables of types other than funcref or externref ({})",
ty
))
}
}; };
if let Some(max) = table.maximum { if let Some(max) = table.maximum {
if max < table.minimum { if max < table.minimum {
@@ -184,7 +254,7 @@ impl LinearTable {
} }
let table_minimum = usize::try_from(table.minimum) let table_minimum = usize::try_from(table.minimum)
.map_err(|_| "Table minimum is bigger than usize".to_string())?; .map_err(|_| "Table minimum is bigger than usize".to_string())?;
let mut vec = vec![VMCallerCheckedAnyfunc::default(); table_minimum]; let mut vec = vec![RawTableElement::default(); table_minimum];
let base = vec.as_mut_ptr(); let base = vec.as_mut_ptr();
match style { match style {
TableStyle::CallerChecksSignature => Ok(Self { TableStyle::CallerChecksSignature => Ok(Self {
@@ -252,7 +322,7 @@ impl Table for LinearTable {
/// ///
/// Returns `None` if table can't be grown by the specified amount /// Returns `None` if table can't be grown by the specified amount
/// of elements, otherwise returns the previous size of the table. /// of elements, otherwise returns the previous size of the table.
fn grow(&self, delta: u32) -> Option<u32> { fn grow(&self, delta: u32, init_value: TableElement) -> Option<u32> {
let mut vec_guard = self.vec.lock().unwrap(); let mut vec_guard = self.vec.lock().unwrap();
let vec = vec_guard.borrow_mut(); let vec = vec_guard.borrow_mut();
let size = self.size(); let size = self.size();
@@ -260,10 +330,26 @@ impl Table for LinearTable {
if self.maximum.map_or(false, |max| new_len > max) { if self.maximum.map_or(false, |max| new_len > max) {
return None; return None;
} }
vec.resize( if new_len == size {
usize::try_from(new_len).unwrap(), debug_assert_eq!(delta, 0);
VMCallerCheckedAnyfunc::default(), return Some(size);
); }
// Update the ref count
let element = match init_value {
TableElement::ExternRef(extern_ref) => {
let extern_ref: VMExternRef = extern_ref.into();
// We reduce the amount we increment by because `into` prevents
// dropping `init_value` (which is a caller-inc'd ref).
(new_len as usize)
.checked_sub(size as usize + 1)
.map(|val| extern_ref.ref_inc_by(val));
RawTableElement { extern_ref }
}
TableElement::FuncRef(func_ref) => RawTableElement { func_ref },
};
vec.resize(usize::try_from(new_len).unwrap(), element);
// update table definition // update table definition
unsafe { unsafe {
@@ -278,9 +364,16 @@ impl Table for LinearTable {
/// Get reference to the specified element. /// Get reference to the specified element.
/// ///
/// Returns `None` if the index is out of bounds. /// Returns `None` if the index is out of bounds.
fn get(&self, index: u32) -> Option<VMCallerCheckedAnyfunc> { fn get(&self, index: u32) -> Option<TableElement> {
let vec_guard = self.vec.lock().unwrap(); let vec_guard = self.vec.lock().unwrap();
vec_guard.borrow().get(index as usize).cloned() let raw_data = vec_guard.borrow().get(index as usize).cloned()?;
Some(match self.table.ty {
ValType::ExternRef => {
TableElement::ExternRef(unsafe { raw_data.extern_ref.ref_clone() }.into())
}
ValType::FuncRef => TableElement::FuncRef(unsafe { raw_data.func_ref }),
_ => todo!("getting invalid type from table, handle this error"),
})
} }
/// Set reference to the specified element. /// Set reference to the specified element.
@@ -288,12 +381,32 @@ impl Table for LinearTable {
/// # Errors /// # Errors
/// ///
/// Returns an error if the index is out of bounds. /// Returns an error if the index is out of bounds.
fn set(&self, index: u32, func: VMCallerCheckedAnyfunc) -> Result<(), Trap> { fn set(&self, index: u32, reference: TableElement) -> Result<(), Trap> {
let mut vec_guard = self.vec.lock().unwrap(); let mut vec_guard = self.vec.lock().unwrap();
let vec = vec_guard.borrow_mut(); let vec = vec_guard.borrow_mut();
match vec.get_mut(index as usize) { match vec.get_mut(index as usize) {
Some(slot) => { Some(slot) => {
*slot = func; match (self.table.ty, reference) {
(ValType::ExternRef, TableElement::ExternRef(extern_ref)) => {
let extern_ref = extern_ref.into();
unsafe {
let elem = &mut *slot;
elem.extern_ref.ref_drop();
elem.extern_ref = extern_ref
}
}
(ValType::FuncRef, r @ TableElement::FuncRef(_)) => {
let element_data = r.into();
*slot = element_data;
}
// This path should never be hit by the generated code due to Wasm
// validation.
(ty, v) => panic!(
"Attempted to set a table of type {} with the value {:?}",
ty, v
),
};
Ok(()) Ok(())
} }
None => Err(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds)), None => Err(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds)),

View File

@@ -86,7 +86,9 @@ impl TrapCode {
Self::HeapSetterOutOfBounds => "memory out of bounds: data segment does not fit", Self::HeapSetterOutOfBounds => "memory out of bounds: data segment does not fit",
Self::HeapAccessOutOfBounds => "out of bounds memory access", Self::HeapAccessOutOfBounds => "out of bounds memory access",
Self::HeapMisaligned => "misaligned heap", Self::HeapMisaligned => "misaligned heap",
Self::TableSetterOutOfBounds => "table out of bounds: elements segment does not fit", Self::TableSetterOutOfBounds => {
"out of bounds table access: elements segment does not fit"
}
Self::TableAccessOutOfBounds => "undefined element: out of bounds table access", Self::TableAccessOutOfBounds => "undefined element: out of bounds table access",
Self::OutOfBounds => "out of bounds", Self::OutOfBounds => "out of bounds",
Self::IndirectCallToNull => "uninitialized element", Self::IndirectCallToNull => "uninitialized element",

View File

@@ -4,11 +4,13 @@
//! This file declares `VMContext` and several related structs which contain //! This file declares `VMContext` and several related structs which contain
//! fields that compiled wasm code accesses directly. //! fields that compiled wasm code accesses directly.
use crate::func_data_registry::VMFuncRef;
use crate::global::Global; use crate::global::Global;
use crate::instance::Instance; use crate::instance::Instance;
use crate::memory::Memory; use crate::memory::Memory;
use crate::table::Table; use crate::table::Table;
use crate::trap::{Trap, TrapCode}; use crate::trap::{Trap, TrapCode};
use crate::VMExternRef;
use loupe::{MemoryUsage, MemoryUsageTracker, POINTER_BYTE_SIZE}; use loupe::{MemoryUsage, MemoryUsageTracker, POINTER_BYTE_SIZE};
use std::any::Any; use std::any::Any;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -22,7 +24,7 @@ use std::u32;
/// ///
/// It may either be a pointer to the [`VMContext`] if it's a Wasm function /// It may either be a pointer to the [`VMContext`] if it's a Wasm function
/// or a pointer to arbitrary data controlled by the host if it's a host function. /// or a pointer to arbitrary data controlled by the host if it's a host function.
#[derive(Copy, Clone)] #[derive(Copy, Clone, Eq)]
pub union VMFunctionEnvironment { pub union VMFunctionEnvironment {
/// Wasm functions take a pointer to [`VMContext`]. /// Wasm functions take a pointer to [`VMContext`].
pub vmctx: *mut VMContext, pub vmctx: *mut VMContext,
@@ -51,6 +53,14 @@ impl std::cmp::PartialEq for VMFunctionEnvironment {
} }
} }
impl std::hash::Hash for VMFunctionEnvironment {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe {
self.vmctx.hash(state);
}
}
}
impl MemoryUsage for VMFunctionEnvironment { impl MemoryUsage for VMFunctionEnvironment {
fn size_of_val(&self, _: &mut dyn MemoryUsageTracker) -> usize { fn size_of_val(&self, _: &mut dyn MemoryUsageTracker) -> usize {
mem::size_of_val(self) mem::size_of_val(self)
@@ -516,6 +526,8 @@ pub union VMGlobalDefinitionStorage {
as_u64: u64, as_u64: u64,
as_f64: f64, as_f64: f64,
as_u128: u128, as_u128: u128,
as_funcref: VMFuncRef,
as_externref: VMExternRef,
bytes: [u8; 16], bytes: [u8; 16],
} }
@@ -547,7 +559,7 @@ pub struct VMGlobalDefinition {
#[cfg(test)] #[cfg(test)]
mod test_vmglobal_definition { mod test_vmglobal_definition {
use super::VMGlobalDefinition; use super::VMGlobalDefinition;
use crate::{ModuleInfo, VMOffsets}; use crate::{ModuleInfo, VMFuncRef, VMOffsets};
use more_asserts::assert_ge; use more_asserts::assert_ge;
use std::mem::{align_of, size_of}; use std::mem::{align_of, size_of};
@@ -557,6 +569,7 @@ mod test_vmglobal_definition {
assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<i64>()); assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<i64>());
assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f32>()); assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f32>());
assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f64>()); assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f64>());
assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<VMFuncRef>());
assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<[u8; 16]>()); assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<[u8; 16]>());
} }
@@ -700,6 +713,44 @@ impl VMGlobalDefinition {
&mut self.storage.as_f64 &mut self.storage.as_f64
} }
/// Return a reference to the value as a `VMFuncRef`.
///
/// If this is not a `VMFuncRef` typed global it is unspecified what value is returned.
pub fn to_funcref(&self) -> VMFuncRef {
unsafe { self.storage.as_funcref }
}
/// Return a mutable reference to the value as a `VMFuncRef`.
///
/// # Safety
///
/// It is the callers responsibility to make sure the global has `VMFuncRef` type.
/// Until the returned borrow is dropped, reads and writes of this global
/// must be done exclusively through this borrow. That includes reads and
/// writes of globals inside wasm functions.
pub unsafe fn as_funcref_mut(&mut self) -> &mut VMFuncRef {
&mut self.storage.as_funcref
}
/// Return a mutable reference to the value as an `VMExternRef`.
///
/// # Safety
///
/// It is the callers responsibility to make sure the global has I32 type.
/// Until the returned borrow is dropped, reads and writes of this global
/// must be done exclusively through this borrow. That includes reads and
/// writes of globals inside wasm functions.
pub unsafe fn as_externref_mut(&mut self) -> &mut VMExternRef {
&mut self.storage.as_externref
}
/// Return a reference to the value as an `VMExternRef`.
///
/// If this is not an I64 typed global it is unspecified what value is returned.
pub fn to_externref(&self) -> VMExternRef {
unsafe { self.storage.as_externref }
}
/// Return a reference to the value as an u128. /// Return a reference to the value as an u128.
/// ///
/// If this is not an V128 typed global it is unspecified what value is returned. /// If this is not an V128 typed global it is unspecified what value is returned.
@@ -784,7 +835,7 @@ impl Default for VMSharedSignatureIndex {
/// The VM caller-checked "anyfunc" record, for caller-side signature checking. /// The VM caller-checked "anyfunc" record, for caller-side signature checking.
/// It consists of the actual function pointer and a signature id to be checked /// It consists of the actual function pointer and a signature id to be checked
/// by the caller. /// by the caller.
#[derive(Debug, Clone, MemoryUsage)] #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, MemoryUsage)]
#[repr(C)] #[repr(C)]
pub struct VMCallerCheckedAnyfunc { pub struct VMCallerCheckedAnyfunc {
/// Function body. /// Function body.
@@ -873,7 +924,7 @@ impl VMBuiltinFunctionIndex {
Self(6) Self(6)
} }
/// Returns an index for wasm's `memory.copy` for locally defined memories. /// Returns an index for wasm's `memory.copy` for locally defined memories.
pub const fn get_local_memory_copy_index() -> Self { pub const fn get_memory_copy_index() -> Self {
Self(7) Self(7)
} }
/// Returns an index for wasm's `memory.copy` for imported memories. /// Returns an index for wasm's `memory.copy` for imported memories.
@@ -900,9 +951,57 @@ impl VMBuiltinFunctionIndex {
pub const fn get_raise_trap_index() -> Self { pub const fn get_raise_trap_index() -> Self {
Self(13) Self(13)
} }
/// Returns an index for wasm's `table.size` instruction for local tables.
pub const fn get_table_size_index() -> Self {
Self(14)
}
/// Returns an index for wasm's `table.size` instruction for imported tables.
pub const fn get_imported_table_size_index() -> Self {
Self(15)
}
/// Returns an index for wasm's `table.grow` instruction for local tables.
pub const fn get_table_grow_index() -> Self {
Self(16)
}
/// Returns an index for wasm's `table.grow` instruction for imported tables.
pub const fn get_imported_table_grow_index() -> Self {
Self(17)
}
/// Returns an index for wasm's `table.get` instruction for local tables.
pub const fn get_table_get_index() -> Self {
Self(18)
}
/// Returns an index for wasm's `table.get` instruction for imported tables.
pub const fn get_imported_table_get_index() -> Self {
Self(19)
}
/// Returns an index for wasm's `table.set` instruction for local tables.
pub const fn get_table_set_index() -> Self {
Self(20)
}
/// Returns an index for wasm's `table.set` instruction for imported tables.
pub const fn get_imported_table_set_index() -> Self {
Self(21)
}
/// Returns an index for wasm's `func.ref` instruction.
pub const fn get_func_ref_index() -> Self {
Self(22)
}
/// Returns an index for wasm's `table.fill` instruction for local tables.
pub const fn get_table_fill_index() -> Self {
Self(23)
}
/// Returns an index for a function to increment the externref count.
pub const fn get_externref_inc_index() -> Self {
Self(24)
}
/// Returns an index for a function to decrement the externref count.
pub const fn get_externref_dec_index() -> Self {
Self(25)
}
/// Returns the total number of builtin functions. /// Returns the total number of builtin functions.
pub const fn builtin_functions_total_number() -> u32 { pub const fn builtin_functions_total_number() -> u32 {
14 26
} }
/// Return the index as an u32 number. /// Return the index as an u32 number.
@@ -929,37 +1028,61 @@ impl VMBuiltinFunctionsArray {
let mut ptrs = [0; Self::len()]; let mut ptrs = [0; Self::len()];
ptrs[VMBuiltinFunctionIndex::get_memory32_grow_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_memory32_grow_index().index() as usize] =
wasmer_memory32_grow as usize; wasmer_vm_memory32_grow as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_memory32_grow_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_imported_memory32_grow_index().index() as usize] =
wasmer_imported_memory32_grow as usize; wasmer_vm_imported_memory32_grow as usize;
ptrs[VMBuiltinFunctionIndex::get_memory32_size_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_memory32_size_index().index() as usize] =
wasmer_memory32_size as usize; wasmer_vm_memory32_size as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_memory32_size_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_imported_memory32_size_index().index() as usize] =
wasmer_imported_memory32_size as usize; wasmer_vm_imported_memory32_size as usize;
ptrs[VMBuiltinFunctionIndex::get_table_copy_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_table_copy_index().index() as usize] =
wasmer_table_copy as usize; wasmer_vm_table_copy as usize;
ptrs[VMBuiltinFunctionIndex::get_table_init_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_table_init_index().index() as usize] =
wasmer_table_init as usize; wasmer_vm_table_init as usize;
ptrs[VMBuiltinFunctionIndex::get_elem_drop_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_elem_drop_index().index() as usize] =
wasmer_elem_drop as usize; wasmer_vm_elem_drop as usize;
ptrs[VMBuiltinFunctionIndex::get_local_memory_copy_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_memory_copy_index().index() as usize] =
wasmer_local_memory_copy as usize; wasmer_vm_memory32_copy as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_memory_copy_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_imported_memory_copy_index().index() as usize] =
wasmer_imported_memory_copy as usize; wasmer_vm_imported_memory32_copy as usize;
ptrs[VMBuiltinFunctionIndex::get_memory_fill_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_memory_fill_index().index() as usize] =
wasmer_memory_fill as usize; wasmer_vm_memory32_fill as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_memory_fill_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_imported_memory_fill_index().index() as usize] =
wasmer_imported_memory_fill as usize; wasmer_vm_imported_memory32_fill as usize;
ptrs[VMBuiltinFunctionIndex::get_memory_init_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_memory_init_index().index() as usize] =
wasmer_memory_init as usize; wasmer_vm_memory32_init as usize;
ptrs[VMBuiltinFunctionIndex::get_data_drop_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_data_drop_index().index() as usize] =
wasmer_data_drop as usize; wasmer_vm_data_drop as usize;
ptrs[VMBuiltinFunctionIndex::get_raise_trap_index().index() as usize] = ptrs[VMBuiltinFunctionIndex::get_raise_trap_index().index() as usize] =
wasmer_raise_trap as usize; wasmer_vm_raise_trap as usize;
ptrs[VMBuiltinFunctionIndex::get_table_size_index().index() as usize] =
wasmer_vm_table_size as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_table_size_index().index() as usize] =
wasmer_vm_imported_table_size as usize;
ptrs[VMBuiltinFunctionIndex::get_table_grow_index().index() as usize] =
wasmer_vm_table_grow as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_table_grow_index().index() as usize] =
wasmer_vm_imported_table_grow as usize;
ptrs[VMBuiltinFunctionIndex::get_table_get_index().index() as usize] =
wasmer_vm_table_get as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_table_get_index().index() as usize] =
wasmer_vm_imported_table_get as usize;
ptrs[VMBuiltinFunctionIndex::get_table_set_index().index() as usize] =
wasmer_vm_table_set as usize;
ptrs[VMBuiltinFunctionIndex::get_imported_table_set_index().index() as usize] =
wasmer_vm_imported_table_set as usize;
ptrs[VMBuiltinFunctionIndex::get_func_ref_index().index() as usize] =
wasmer_vm_func_ref as usize;
ptrs[VMBuiltinFunctionIndex::get_table_fill_index().index() as usize] =
wasmer_vm_table_fill as usize;
ptrs[VMBuiltinFunctionIndex::get_externref_inc_index().index() as usize] =
wasmer_vm_externref_inc as usize;
ptrs[VMBuiltinFunctionIndex::get_externref_dec_index().index() as usize] =
wasmer_vm_externref_dec as usize;
debug_assert!(ptrs.iter().cloned().all(|p| p != 0)); debug_assert!(ptrs.iter().cloned().all(|p| p != 0));

View File

@@ -335,6 +335,24 @@ impl VMOffsets {
} }
} }
/// Offsets for [`VMFuncRef`].
///
/// [`VMFuncRef`]: crate::func_data_registry::VMFuncRef
impl VMOffsets {
/// The offset to the pointer to the anyfunc inside the ref.
#[allow(clippy::erasing_op)]
pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
0 * self.pointer_size
}
/// Return the size of [`VMFuncRef`].
///
/// [`VMFuncRef`]: crate::func_data_registry::VMFuncRef
pub const fn size_of_vm_funcref(&self) -> u8 {
1 * self.pointer_size
}
}
/// Offsets for [`VMContext`]. /// Offsets for [`VMContext`].
/// ///
/// [`VMContext`]: crate::vmcontext::VMContext /// [`VMContext`]: crate::vmcontext::VMContext

View File

@@ -34,7 +34,6 @@ cranelift::spec::simd::simd_i8x16_sat_arith on aarch64
cranelift::spec::simd::simd_lane on aarch64 cranelift::spec::simd::simd_lane on aarch64
cranelift::spec::skip_stack_guard_page on aarch64 cranelift::spec::skip_stack_guard_page on aarch64
# SIMD changes # SIMD changes
# due to breaking changes in the SIMD proposal, we have to disable these spec tests # 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 # note we've not pulled in the updated spec tests yet, so expect more breakage

View File

@@ -16,8 +16,8 @@ use wasmer_types::{
TableIndex, TableIndex,
}; };
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMContext, VMFunctionBody, FuncDataRegistry, FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMContext,
VMSharedSignatureIndex, VMTrampoline, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
}; };
/// Serializable struct for the artifact /// Serializable struct for the artifact
@@ -44,6 +44,7 @@ pub struct DummyArtifact {
finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>, finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>, finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>, signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
func_data_registry: Arc<FuncDataRegistry>,
} }
extern "C" fn dummy_function(_context: *mut VMContext) { extern "C" fn dummy_function(_context: *mut VMContext) {
@@ -184,6 +185,7 @@ impl DummyArtifact {
finished_function_call_trampolines, finished_function_call_trampolines,
finished_dynamic_function_trampolines, finished_dynamic_function_trampolines,
signatures, signatures,
func_data_registry: engine.func_data().clone(),
}) })
} }
} }
@@ -237,6 +239,10 @@ impl Artifact for DummyArtifact {
&self.signatures &self.signatures
} }
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
fn serialize(&self) -> Result<Vec<u8>, SerializeError> { fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
let bytes = bincode::serialize(&self.metadata) let bytes = bincode::serialize(&self.metadata)

View File

@@ -6,7 +6,10 @@ use std::sync::Arc;
use wasmer_compiler::{CompileError, Features, Target}; use wasmer_compiler::{CompileError, Features, Target};
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
use wasmer_types::FunctionType; use wasmer_types::FunctionType;
use wasmer_vm::{SignatureRegistry, VMContext, VMFunctionBody, VMSharedSignatureIndex}; use wasmer_vm::{
FuncDataRegistry, SignatureRegistry, VMCallerCheckedAnyfunc, VMContext, VMFuncRef,
VMFunctionBody, VMSharedSignatureIndex,
};
#[allow(dead_code)] #[allow(dead_code)]
extern "C" fn dummy_trampoline( extern "C" fn dummy_trampoline(
@@ -21,6 +24,7 @@ extern "C" fn dummy_trampoline(
#[derive(Clone, MemoryUsage)] #[derive(Clone, MemoryUsage)]
pub struct DummyEngine { pub struct DummyEngine {
signatures: Arc<SignatureRegistry>, signatures: Arc<SignatureRegistry>,
func_data: Arc<FuncDataRegistry>,
features: Arc<Features>, features: Arc<Features>,
target: Arc<Target>, target: Arc<Target>,
engine_id: EngineId, engine_id: EngineId,
@@ -31,6 +35,7 @@ impl DummyEngine {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
signatures: Arc::new(SignatureRegistry::new()), signatures: Arc::new(SignatureRegistry::new()),
func_data: Arc::new(FuncDataRegistry::new()),
features: Arc::new(Default::default()), features: Arc::new(Default::default()),
target: Arc::new(Default::default()), target: Arc::new(Default::default()),
engine_id: EngineId::default(), engine_id: EngineId::default(),
@@ -40,6 +45,11 @@ impl DummyEngine {
pub fn features(&self) -> &Features { pub fn features(&self) -> &Features {
&self.features &self.features
} }
/// Shared func metadata registry.
pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
&self.func_data
}
} }
impl Engine for DummyEngine { impl Engine for DummyEngine {
@@ -53,6 +63,10 @@ impl Engine for DummyEngine {
self.signatures.register(func_type) self.signatures.register(func_type)
} }
fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
self.func_data.register(func_data)
}
/// Lookup a signature /// Lookup a signature
fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> { fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
self.signatures.lookup(sig) self.signatures.lookup(sig)

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