mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-09 14:18:20 +00:00
resolve conflict, replace two primary map to hash map
This commit is contained in:
@@ -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",
|
|
||||||
]
|
|
||||||
2
.github/workflows/documentation.yaml
vendored
2
.github/workflows/documentation.yaml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/lint.yaml
vendored
2
.github/workflows/lint.yaml
vendored
@@ -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)
|
||||||
|
|||||||
14
.github/workflows/main.yaml
vendored
14
.github/workflows/main.yaml
vendored
@@ -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
|
||||||
|
|||||||
@@ -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
15
Cargo.lock
generated
@@ -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
121
Makefile
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
191
docs/ja/README.md
Normal 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 は_どんな場所でも_利用できます。
|
||||||
|
|
||||||
|
| | 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)
|
||||||
@@ -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
4
fuzz/Cargo.lock
generated
@@ -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
9
fuzzbuzz.yaml
Normal 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
|
||||||
@@ -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",
|
||||||
|
]
|
||||||
|
|||||||
79
lib/api/src/externals/function.rs
vendored
79
lib/api/src/externals/function.rs
vendored
@@ -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::*;
|
||||||
|
|||||||
2
lib/api/src/externals/global.rs
vendored
2
lib/api/src/externals/global.rs
vendored
@@ -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.
|
||||||
|
|||||||
27
lib/api/src/externals/table.rs
vendored
27
lib/api/src/externals/table.rs
vendored
@@ -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`
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
|||||||
497
lib/api/tests/reference_types.rs
Normal file
497
lib/api/tests/reference_types.rs
Normal 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
22
lib/c-api/CHANGELOG.md
Normal 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).
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
35
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
@@ -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]
|
||||||
|
|||||||
22
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
22
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
@@ -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]
|
||||||
|
|||||||
22
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
22
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
@@ -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]
|
||||||
|
|||||||
245
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
245
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
20
lib/c-api/src/wasm_c_api/externals/table.rs
vendored
20
lib/c-api/src/wasm_c_api/externals/table.rs
vendored
@@ -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]
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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<_>>()
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
@@ -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<()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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))),
|
||||||
|
|||||||
@@ -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| {
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
|||||||
115
lib/deprecated/runtime-core/Cargo.lock
generated
115
lib/deprecated/runtime-core/Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
33
lib/emscripten/src/env/unix/mod.rs
vendored
33
lib/emscripten/src/env/unix/mod.rs
vendored
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
20
lib/emscripten/src/env/windows/mod.rs
vendored
20
lib/emscripten/src/env/windows/mod.rs
vendored
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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: {}",
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|
||||||
|
|||||||
@@ -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
295
lib/types/src/extern_ref.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|||||||
@@ -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, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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),
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
121
lib/vm/src/func_data_registry.rs
Normal file
121
lib/vm/src/func_data_registry.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)),
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user