mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-07 13:18:20 +00:00
Merge branch 'master' into feature/host-env-prototype
This commit is contained in:
49
.github/CODEOWNERS
vendored
49
.github/CODEOWNERS
vendored
@@ -1,25 +1,24 @@
|
|||||||
#
|
benches @syrusakbary
|
||||||
src/ @syrusakbary @MarkMcCaskey
|
examples @Hywan @jubianchi
|
||||||
|
fuzz @syrusakbary
|
||||||
# Backends
|
lib/api @syrusakbary @Hywan @MarkMcCaskey
|
||||||
lib/compiler-singlepass @losfair @nlewycky
|
lib/c-api @Hywan @MarkMcCaskey @jubianchi
|
||||||
lib/compiler-cranelift @syrusakbary @nlewycky
|
lib/cache @syrusakbary @Hywan
|
||||||
lib/compiler-llvm @nlewycky @losfair
|
lib/cli @syrusakbary @MarkMcCaskey
|
||||||
|
lib/compiler @syrusakbary @nlewycky @losfair @Hywan @MarkMcCaskey
|
||||||
# Runtime
|
lib/compiler-cranelift @nlewycky @syrusakbary
|
||||||
lib/runtime @syrusakbary @Hywan
|
lib/compiler-llvm @nlewycky @losfair
|
||||||
lib/c-api @Hywan
|
lib/compiler-singlepass @losfair @nlewycky
|
||||||
|
lib/deprecated @Hywan @MarkMcCaskey
|
||||||
# Frontend integrations
|
lib/emscripten @MarkMcCaskey
|
||||||
|
lib/engine @syrusakbary @MarkMcCaskey @Hywan
|
||||||
## Emscripten
|
lib/engine-jit @syrusakbary @MarkMcCaskey @Hywan
|
||||||
lib/emscripten @MarkMcCaskey @syrusakbary
|
lib/engine-native @syrusakbary @MarkMcCaskey @Hywan
|
||||||
|
lib/engine-object-file @syrusakbary @MarkMcCaskey @Hywan
|
||||||
## WASI
|
lib/object @syrusakbary @nlewycky
|
||||||
lib/wasi @MarkMcCaskey
|
lib/vm @syrusakbary @nlewycky @MarkMcCaskey
|
||||||
|
lib/wasi @MarkMcCaskey
|
||||||
# Examples
|
lib/wasi-experimental-io-devices @MarkMcCaskey
|
||||||
examples @syrusakbary
|
lib/wasmer-types @syrusakbary @Hywan
|
||||||
|
scripts @syrusakbary
|
||||||
# Examples
|
tests @MarkMcCaskey
|
||||||
tests @syrusakbary @MarkMcCaskey
|
|
||||||
2
.github/workflows/main.yaml
vendored
2
.github/workflows/main.yaml
vendored
@@ -143,8 +143,8 @@ jobs:
|
|||||||
- run: make test
|
- run: make test
|
||||||
- name: Build and Test C API
|
- name: Build and Test C API
|
||||||
run: |
|
run: |
|
||||||
make build-capi
|
|
||||||
make test-capi
|
make test-capi
|
||||||
|
make build-capi
|
||||||
if: matrix.os != 'windows-latest'
|
if: matrix.os != 'windows-latest'
|
||||||
- name: Build C API on Windows
|
- name: Build C API on Windows
|
||||||
run: make build-capi
|
run: make build-capi
|
||||||
|
|||||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -7,9 +7,21 @@
|
|||||||
|
|
||||||
## **[Unreleased]**
|
## **[Unreleased]**
|
||||||
|
|
||||||
- [#1710](https://github.com/wasmerio/wasmer/pull/1710) Memory for function call trampolines is now owned by the Artifact.
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- [#1649](https://github.com/wasmerio/wasmer/pull/1649) Add outline of migration to 1.0.0 docs.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [#1764](https://github.com/wasmerio/wasmer/pull/1764) Fix bug in WASI `path_rename` allowing renamed files to be 1 directory below a preopened directory.
|
||||||
|
|
||||||
|
## 1.0.0-alpha5 - 2020-11-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#1761](https://github.com/wasmerio/wasmer/pull/1761) Implement the `wasm_trap_t**` argument of `wasm_instance_new` in the Wasm C API.
|
||||||
- [#1687](https://github.com/wasmerio/wasmer/pull/1687) Add basic table example; fix ownership of local memory and local table metadata in the VM.
|
- [#1687](https://github.com/wasmerio/wasmer/pull/1687) Add basic table example; fix ownership of local memory and local table metadata in the VM.
|
||||||
- [#1751](https://github.com/wasmerio/wasmer/pull/1751) Implement `wasm_trap_t` inside a function declared with `wasm_func_new_with_env` in the Wasm C API.
|
- [#1751](https://github.com/wasmerio/wasmer/pull/1751) Implement `wasm_trap_t` inside a function declared with `wasm_func_new_with_env` in the Wasm C API.
|
||||||
- [#1741](https://github.com/wasmerio/wasmer/pull/1741) Implement `wasm_memory_type` in the Wasm C API.
|
- [#1741](https://github.com/wasmerio/wasmer/pull/1741) Implement `wasm_memory_type` in the Wasm C API.
|
||||||
@@ -20,15 +32,26 @@
|
|||||||
- [#1715](https://github.com/wasmerio/wasmer/pull/1715) Register errors from `wasm_module_serialize` in the Wasm C API.
|
- [#1715](https://github.com/wasmerio/wasmer/pull/1715) Register errors from `wasm_module_serialize` in the Wasm C API.
|
||||||
- [#1709](https://github.com/wasmerio/wasmer/pull/1709) Implement `wasm_module_name` and `wasm_module_set_name` in the Wasm(er) C API.
|
- [#1709](https://github.com/wasmerio/wasmer/pull/1709) Implement `wasm_module_name` and `wasm_module_set_name` in the Wasm(er) C API.
|
||||||
- [#1700](https://github.com/wasmerio/wasmer/pull/1700) Implement `wasm_externtype_copy` in the Wasm C API.
|
- [#1700](https://github.com/wasmerio/wasmer/pull/1700) Implement `wasm_externtype_copy` in the Wasm C API.
|
||||||
|
- [#1785](https://github.com/wasmerio/wasmer/pull/1785) Add more examples on the Rust API.
|
||||||
|
- [#1783](https://github.com/wasmerio/wasmer/pull/1783) Handle initialized but empty results in `wasm_func_call` in the Wasm C API.
|
||||||
|
- [#1780](https://github.com/wasmerio/wasmer/pull/1780) Implement new SIMD zero-extend loads in compiler-llvm.
|
||||||
|
- [#1754](https://github.com/wasmerio/wasmer/pull/1754) Implement aarch64 ABI for compiler-llvm.
|
||||||
|
- [#1693](https://github.com/wasmerio/wasmer/pull/1693) Add `wasmer create-exe` subcommand.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- [#1772](https://github.com/wasmerio/wasmer/pull/1772) Remove lifetime parameter from `NativeFunc`.
|
- [#1772](https://github.com/wasmerio/wasmer/pull/1772) Remove lifetime parameter from `NativeFunc`.
|
||||||
- [#1762](https://github.com/wasmerio/wasmer/pull/1762) Allow the `=` sign in a WASI environment variable value.
|
- [#1762](https://github.com/wasmerio/wasmer/pull/1762) Allow the `=` sign in a WASI environment variable value.
|
||||||
|
- [#1710](https://github.com/wasmerio/wasmer/pull/1710) Memory for function call trampolines is now owned by the Artifact.
|
||||||
|
- [#1781](https://github.com/wasmerio/wasmer/pull/1781) Cranelift upgrade to 0.67.
|
||||||
|
- [#1777](https://github.com/wasmerio/wasmer/pull/1777) Wasmparser update to 0.65.
|
||||||
|
- [#1775](https://github.com/wasmerio/wasmer/pull/1775) Improve LimitingTunables implementation.
|
||||||
|
- [#1720](https://github.com/wasmerio/wasmer/pull/1720) Autodetect llvm regardless of architecture.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- [#1718](https://github.com/wasmerio/wasmer/pull/1718) Fix panic in the API in some situations when the memory's min bound was greater than the memory's max bound.
|
- [#1718](https://github.com/wasmerio/wasmer/pull/1718) Fix panic in the API in some situations when the memory's min bound was greater than the memory's max bound.
|
||||||
|
- [#1731](https://github.com/wasmerio/wasmer/pull/1731) In compiler-llvm always load before store, to trigger any traps before any bytes are written.
|
||||||
|
|
||||||
## 1.0.0-alpha4 - 2020-10-08
|
## 1.0.0-alpha4 - 2020-10-08
|
||||||
|
|
||||||
@@ -41,6 +64,7 @@
|
|||||||
- [#1690](https://github.com/wasmerio/wasmer/pull/1690) Fix `wasm_memorytype_limits` where `min` and `max` represents pages, not bytes. Additionally, fixes the max limit sentinel value.
|
- [#1690](https://github.com/wasmerio/wasmer/pull/1690) Fix `wasm_memorytype_limits` where `min` and `max` represents pages, not bytes. Additionally, fixes the max limit sentinel value.
|
||||||
- [#1671](https://github.com/wasmerio/wasmer/pull/1671) Fix probestack firing inappropriately, and sometimes over/under allocating stack.
|
- [#1671](https://github.com/wasmerio/wasmer/pull/1671) Fix probestack firing inappropriately, and sometimes over/under allocating stack.
|
||||||
- [#1660](https://github.com/wasmerio/wasmer/pull/1660) Fix issue preventing map-dir aliases starting with `/` from working properly.
|
- [#1660](https://github.com/wasmerio/wasmer/pull/1660) Fix issue preventing map-dir aliases starting with `/` from working properly.
|
||||||
|
- [#1624](https://github.com/wasmerio/wasmer/pull/1624) Add Value::I32/Value::I64 converters from unsigned ints.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- [#1682](https://github.com/wasmerio/wasmer/pull/1682) Improve error reporting when making a memory with invalid settings.
|
- [#1682](https://github.com/wasmerio/wasmer/pull/1682) Improve error reporting when making a memory with invalid settings.
|
||||||
|
|||||||
671
Cargo.lock
generated
671
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
52
Cargo.toml
52
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-workspace"
|
name = "wasmer-workspace"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer workspace"
|
description = "Wasmer workspace"
|
||||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
@@ -10,20 +10,20 @@ publish = false
|
|||||||
autoexamples = false
|
autoexamples = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer = { version = "1.0.0-alpha4", path = "lib/api", default-features = false }
|
wasmer = { version = "1.0.0-alpha5", path = "lib/api", default-features = false }
|
||||||
wasmer-compiler = { version = "1.0.0-alpha4", path = "lib/compiler" }
|
wasmer-compiler = { version = "1.0.0-alpha5", path = "lib/compiler" }
|
||||||
wasmer-compiler-cranelift = { version = "1.0.0-alpha4", path = "lib/compiler-cranelift", optional = true }
|
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "lib/compiler-cranelift", optional = true }
|
||||||
wasmer-compiler-singlepass = { version = "1.0.0-alpha4", path = "lib/compiler-singlepass", optional = true }
|
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "lib/compiler-singlepass", optional = true }
|
||||||
wasmer-compiler-llvm = { version = "1.0.0-alpha4", path = "lib/compiler-llvm", optional = true }
|
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "lib/compiler-llvm", optional = true }
|
||||||
wasmer-engine = { version = "1.0.0-alpha4", path = "lib/engine" }
|
wasmer-engine = { version = "1.0.0-alpha5", path = "lib/engine" }
|
||||||
wasmer-engine-jit = { version = "1.0.0-alpha4", path = "lib/engine-jit", optional = true }
|
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "lib/engine-jit", optional = true }
|
||||||
wasmer-engine-native = { version = "1.0.0-alpha4", path = "lib/engine-native", optional = true }
|
wasmer-engine-native = { version = "1.0.0-alpha5", path = "lib/engine-native", optional = true }
|
||||||
wasmer-engine-object-file = { version = "1.0.0-alpha4", path = "lib/engine-object-file", optional = true }
|
wasmer-engine-object-file = { version = "1.0.0-alpha5", path = "lib/engine-object-file", optional = true }
|
||||||
wasmer-wasi = { version = "1.0.0-alpha4", path = "lib/wasi", optional = true }
|
wasmer-wasi = { version = "1.0.0-alpha5", path = "lib/wasi", optional = true }
|
||||||
wasmer-wast = { version = "1.0.0-alpha4", path = "tests/lib/wast", optional = true }
|
wasmer-wast = { version = "1.0.0-alpha5", path = "tests/lib/wast", optional = true }
|
||||||
wasmer-cache = { version = "1.0.0-alpha4", path = "lib/cache", optional = true }
|
wasmer-cache = { version = "1.0.0-alpha5", path = "lib/cache", optional = true }
|
||||||
wasmer-types = { version = "1.0.0-alpha4", path = "lib/wasmer-types" }
|
wasmer-types = { version = "1.0.0-alpha5", path = "lib/wasmer-types" }
|
||||||
cfg-if = "0.1"
|
cfg-if = "1.0"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
@@ -58,7 +58,7 @@ test-generator = { path = "tests/lib/test-generator" }
|
|||||||
build-deps = "0.1.4"
|
build-deps = "0.1.4"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
rustc_version = "0.2"
|
rustc_version = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
@@ -212,6 +212,11 @@ name = "imported-global"
|
|||||||
path = "examples/imports_global.rs"
|
path = "examples/imports_global.rs"
|
||||||
required-features = ["cranelift"]
|
required-features = ["cranelift"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "tunables-limit-memory"
|
||||||
|
path = "examples/tunables_limit_memory.rs"
|
||||||
|
required-features = ["cranelift"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
path = "examples/wasi.rs"
|
path = "examples/wasi.rs"
|
||||||
@@ -226,3 +231,18 @@ required-features = ["cranelift"]
|
|||||||
name = "memory"
|
name = "memory"
|
||||||
path = "examples/memory.rs"
|
path = "examples/memory.rs"
|
||||||
required-features = ["cranelift"]
|
required-features = ["cranelift"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "instance"
|
||||||
|
path = "examples/instance.rs"
|
||||||
|
required-features = ["cranelift"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "errors"
|
||||||
|
path = "examples/errors.rs"
|
||||||
|
required-features = ["cranelift"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "imported-function-env"
|
||||||
|
path = "examples/imports_function_env.rs"
|
||||||
|
required-features = ["cranelift"]
|
||||||
|
|||||||
51
Makefile
51
Makefile
@@ -61,11 +61,13 @@ ifneq ($(OS), Windows_NT)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
$(info Available compilers: $(bold)$(green)${compilers}$(reset))
|
|
||||||
|
|
||||||
compiler_features_spaced := $(foreach compiler,$(compilers),$(compiler))
|
compiler_features_spaced := $(foreach compiler,$(compilers),$(compiler))
|
||||||
compiler_features := --features "$(compiler_features_spaced)"
|
compiler_features := --features "$(compiler_features_spaced)"
|
||||||
|
|
||||||
|
$(info Available compilers: $(bold)$(green)${compilers}$(reset))
|
||||||
|
$(info Compilers features: $(bold)$(green)${compiler_features}$(reset))
|
||||||
|
$(info Available compilers + engines for test: $(bold)$(green)${test_compilers_engines}$(reset))
|
||||||
|
|
||||||
|
|
||||||
############
|
############
|
||||||
# Building #
|
# Building #
|
||||||
@@ -89,20 +91,41 @@ 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:
|
build-docs-capi:
|
||||||
cd lib/c-api/ && doxygen doxyfile
|
cd lib/c-api/doc/deprecated/ && doxygen doxyfile
|
||||||
|
cargo doc --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,jit,object-file,native,cranelift,wasi
|
||||||
|
|
||||||
# We use cranelift as the default backend for the capi for now
|
# We use cranelift as the default backend for the capi for now
|
||||||
build-capi: build-capi-cranelift-jit
|
build-capi: build-capi-cranelift
|
||||||
|
|
||||||
|
build-capi-singlepass:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,jit,native,object-file,singlepass,wasi
|
||||||
|
|
||||||
build-capi-singlepass-jit:
|
build-capi-singlepass-jit:
|
||||||
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,jit,object-file,singlepass,wasi
|
--no-default-features --features wat,jit,singlepass,wasi
|
||||||
|
|
||||||
|
build-capi-singlepass-native:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,native,singlepass,wasi
|
||||||
|
|
||||||
|
build-capi-singlepass-object-file:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,object-file,singlepass,wasi
|
||||||
|
|
||||||
|
build-capi-cranelift:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,jit,native,object-file,cranelift,wasi
|
||||||
|
|
||||||
build-capi-cranelift-jit:
|
build-capi-cranelift-jit:
|
||||||
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,jit,object-file,cranelift,wasi
|
--no-default-features --features wat,jit,cranelift,wasi
|
||||||
|
|
||||||
build-capi-cranelift-native:
|
build-capi-cranelift-native:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,native,cranelift,wasi
|
||||||
|
|
||||||
|
build-capi-cranelift-object-file:
|
||||||
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,native,object-file,cranelift,wasi
|
--no-default-features --features wat,native,object-file,cranelift,wasi
|
||||||
|
|
||||||
@@ -110,13 +133,21 @@ build-capi-cranelift-system-libffi:
|
|||||||
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,jit,native,object-file,cranelift,wasi,system-libffi
|
--no-default-features --features wat,jit,native,object-file,cranelift,wasi,system-libffi
|
||||||
|
|
||||||
|
build-capi-llvm:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,jit,native,object-file,llvm,wasi
|
||||||
|
|
||||||
build-capi-llvm-jit:
|
build-capi-llvm-jit:
|
||||||
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,jit,object-file,llvm,wasi
|
--no-default-features --features wat,jit,llvm,wasi
|
||||||
|
|
||||||
build-capi-llvm-native:
|
build-capi-llvm-native:
|
||||||
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,native,object-file,llvm,wasi
|
--no-default-features --features wat,native,llvm,wasi
|
||||||
|
|
||||||
|
build-capi-llvm-object-file:
|
||||||
|
cargo build --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
|
--no-default-features --features wat,object-file,llvm,wasi
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# Testing #
|
# Testing #
|
||||||
@@ -163,6 +194,8 @@ test-packages:
|
|||||||
# link the tests against. cargo test doesn't know that the tests will be running
|
# link the tests against. cargo test doesn't know that the tests will be running
|
||||||
# cmake + make to build programs whose dependencies cargo isn't aware of.
|
# cmake + make to build programs whose dependencies cargo isn't aware of.
|
||||||
|
|
||||||
|
test-capi: $(foreach compiler_engine,$(test_compilers_engines),test-capi-$(compiler_engine)) #$(if $(findstring cranelift-jit,$(test_compilers_engines)),test-capi-cranelift-jit-system-libffi)
|
||||||
|
|
||||||
test-capi-singlepass-jit: build-capi-singlepass-jit
|
test-capi-singlepass-jit: build-capi-singlepass-jit
|
||||||
cargo test --manifest-path lib/c-api/Cargo.toml --release \
|
cargo test --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,jit,singlepass,wasi -- --nocapture
|
--no-default-features --features wat,jit,singlepass,wasi -- --nocapture
|
||||||
@@ -187,8 +220,6 @@ test-capi-llvm-native:
|
|||||||
cargo test --manifest-path lib/c-api/Cargo.toml --release \
|
cargo test --manifest-path lib/c-api/Cargo.toml --release \
|
||||||
--no-default-features --features wat,native,llvm,wasi -- --nocapture
|
--no-default-features --features wat,native,llvm,wasi -- --nocapture
|
||||||
|
|
||||||
test-capi: $(foreach compiler_engine,$(test_compilers_engines),test-capi-$(compiler_engine)) $(if $(findstring cranelift-jit,$(test_compilers_engines)),test-capi-cranelift-jit-system-libffi)
|
|
||||||
|
|
||||||
test-wasi-unit:
|
test-wasi-unit:
|
||||||
cargo test --manifest-path lib/wasi/Cargo.toml --release
|
cargo test --manifest-path lib/wasi/Cargo.toml --release
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ qjs >
|
|||||||
[js logo]: ./assets/languages/js.svg
|
[js logo]: ./assets/languages/js.svg
|
||||||
[js integration]: https://github.com/wasmerio/wasmer-js
|
[js integration]: https://github.com/wasmerio/wasmer-js
|
||||||
[`@wasmerio` npm packages]: https://www.npmjs.com/org/wasmer
|
[`@wasmerio` npm packages]: https://www.npmjs.com/org/wasmer
|
||||||
[js docs]: https://docs.wasmer.io/wasmer-js/wasmer-js
|
[js docs]: https://docs.wasmer.io/integrations/js/reference-api
|
||||||
|
|
||||||
[ruby logo]: ./assets/languages/ruby.svg
|
[ruby logo]: ./assets/languages/ruby.svg
|
||||||
[ruby integration]: https://github.com/wasmerio/wasmer-ruby
|
[ruby integration]: https://github.com/wasmerio/wasmer-ruby
|
||||||
|
|||||||
74
docs/deps_dedup.dot
Normal file
74
docs/deps_dedup.dot
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
digraph dependencies {
|
||||||
|
newrank=true;
|
||||||
|
|
||||||
|
n0 [label="wasmer", color=orange];
|
||||||
|
n1 [label="wasmer-compiler", color=orange];
|
||||||
|
n5 [label="wasmer-engine", color=orange];
|
||||||
|
n6 [label="wasmer-engine-jit", color=orange];
|
||||||
|
n7 [label="wasmer-engine-native", color=orange];
|
||||||
|
n8 [label="wasmer-types", color=orange];
|
||||||
|
n9 [label="wasmer-vm", color=orange];
|
||||||
|
n10 [label="wasmer-c-api", color=orange];
|
||||||
|
n11 [label="wasmer-emscripten", color=orange];
|
||||||
|
n12 [label="wasmer-wasi", color=orange];
|
||||||
|
n13 [label="wasmer-cache", color=orange];
|
||||||
|
n14 [label="wasmer-cli", color=orange];
|
||||||
|
|
||||||
|
|
||||||
|
subgraph cluster_compiler {
|
||||||
|
label="Compilers";
|
||||||
|
color=brown;
|
||||||
|
|
||||||
|
n2 [label="wasmer-compiler-cranelift", color=orange];
|
||||||
|
n3 [label="wasmer-compiler-llvm", color=orange];
|
||||||
|
n4 [label="wasmer-compiler-singlepass", color=orange];
|
||||||
|
}
|
||||||
|
|
||||||
|
subgraph cluster_engine {
|
||||||
|
label="Engines";
|
||||||
|
color=brown;
|
||||||
|
|
||||||
|
n6 [label="wasmer-engine-jit", color=orange];
|
||||||
|
n7 [label="wasmer-engine-native", color=orange];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
rank=same;
|
||||||
|
n2;
|
||||||
|
n3;
|
||||||
|
n4;
|
||||||
|
n6;
|
||||||
|
n7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
subgraph cluster_abi {
|
||||||
|
label="Provided ABIs";
|
||||||
|
color=brown;
|
||||||
|
|
||||||
|
n12 [label="wasmer-wasi", color=orange];
|
||||||
|
n11 [label="wasmer-emscripten", color=orange];
|
||||||
|
}
|
||||||
|
|
||||||
|
n14 -> n13 [color=orange, style=dashed];
|
||||||
|
n14 -> n12 [color=orange, style=dashed];
|
||||||
|
n14 -> n11 [color=orange, style=dashed];
|
||||||
|
n13 -> n0 [color=orange, style=dashed];
|
||||||
|
n10 -> n11 [color=orange, style=dashed];
|
||||||
|
n10 -> n12 [color=orange, style=dashed];
|
||||||
|
n11 -> n0 [color=orange, style=dashed];
|
||||||
|
n12 -> n0 [color=orange, style=dashed];
|
||||||
|
n0 -> n2 [color=orange, style=dashed];
|
||||||
|
n0 -> n3 [color=orange, style=dashed];
|
||||||
|
n0 -> n4 [color=orange, style=dashed];
|
||||||
|
n0 -> n6 [color=orange, style=dashed];
|
||||||
|
n0 -> n7 [color=orange, style=dashed];
|
||||||
|
n2 -> n1 [color=orange, style=dashed];
|
||||||
|
n3 -> n1 [color=orange, style=dashed];
|
||||||
|
n4 -> n1 [color=orange, style=dashed];
|
||||||
|
n6 -> n5 [color=orange, style=dashed];
|
||||||
|
n7 -> n5 [color=orange, style=dashed];
|
||||||
|
n5 -> n1 [color=orange, style=dashed];
|
||||||
|
n1 -> n9 [color=orange, style=dashed];
|
||||||
|
n9 -> n8 [color=orange, style=dashed];
|
||||||
|
}
|
||||||
244
docs/deps_dedup.svg
Normal file
244
docs/deps_dedup.svg
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.44.1 (20200629.0846)
|
||||||
|
-->
|
||||||
|
<!-- Title: dependencies Pages: 1 -->
|
||||||
|
<svg width="1067pt" height="554pt"
|
||||||
|
viewBox="0.00 0.00 1067.00 554.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 550)">
|
||||||
|
<title>dependencies</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-550 1063,-550 1063,4 -4,4"/>
|
||||||
|
<g id="clust1" class="cluster">
|
||||||
|
<title>cluster_compiler</title>
|
||||||
|
<polygon fill="none" stroke="brown" points="378,-280 378,-355 1051,-355 1051,-280 378,-280"/>
|
||||||
|
<text text-anchor="middle" x="714.5" y="-339.8" font-family="Times,serif" font-size="14.00">Compilers</text>
|
||||||
|
</g>
|
||||||
|
<g id="clust2" class="cluster">
|
||||||
|
<title>cluster_engine</title>
|
||||||
|
<polygon fill="none" stroke="brown" points="8,-280 8,-355 370,-355 370,-280 8,-280"/>
|
||||||
|
<text text-anchor="middle" x="189" y="-339.8" font-family="Times,serif" font-size="14.00">Engines</text>
|
||||||
|
</g>
|
||||||
|
<g id="clust4" class="cluster">
|
||||||
|
<title>cluster_abi</title>
|
||||||
|
<polygon fill="none" stroke="brown" points="257,-427 257,-502 568,-502 568,-427 257,-427"/>
|
||||||
|
<text text-anchor="middle" x="412.5" y="-486.8" font-family="Times,serif" font-size="14.00">Provided ABIs</text>
|
||||||
|
</g>
|
||||||
|
<!-- n0 -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>n0</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="479" cy="-381" rx="38.19" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="479" y="-377.3" font-family="Times,serif" font-size="14.00">wasmer</text>
|
||||||
|
</g>
|
||||||
|
<!-- n6 -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>n6</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="287" cy="-306" rx="75.29" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="287" y="-302.3" font-family="Times,serif" font-size="14.00">wasmer-engine-jit</text>
|
||||||
|
</g>
|
||||||
|
<!-- n0->n6 -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>n0->n6</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M443.28,-373.99C422.62,-369.9 396.37,-363.65 374,-355 355.71,-347.93 336.5,-337.67 320.81,-328.45"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="322.38,-325.31 312,-323.18 318.78,-331.32 322.38,-325.31"/>
|
||||||
|
</g>
|
||||||
|
<!-- n7 -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>n7</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="105" cy="-306" rx="89.08" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="105" y="-302.3" font-family="Times,serif" font-size="14.00">wasmer-engine-native</text>
|
||||||
|
</g>
|
||||||
|
<!-- n0->n7 -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>n0->n7</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M440.26,-380.88C386.12,-381.13 285.24,-378.02 203,-355 181.25,-348.91 158.5,-338.09 140.41,-328.25"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="141.84,-325.04 131.4,-323.23 138.43,-331.16 141.84,-325.04"/>
|
||||||
|
</g>
|
||||||
|
<!-- n2 -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>n2</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="938" cy="-306" rx="105.08" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="938" y="-302.3" font-family="Times,serif" font-size="14.00">wasmer-compiler-cranelift</text>
|
||||||
|
</g>
|
||||||
|
<!-- n0->n2 -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>n0->n2</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M517.13,-378.78C594.16,-376.05 765.84,-368.62 823,-355 848.67,-348.88 875.98,-337.7 897.54,-327.67"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="899.18,-330.76 906.71,-323.31 896.18,-324.44 899.18,-330.76"/>
|
||||||
|
</g>
|
||||||
|
<!-- n3 -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>n3</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="479" cy="-306" rx="92.88" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="479" y="-302.3" font-family="Times,serif" font-size="14.00">wasmer-compiler-llvm</text>
|
||||||
|
</g>
|
||||||
|
<!-- n0->n3 -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>n0->n3</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M479,-362.7C479,-354.25 479,-343.87 479,-334.37"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="482.5,-334.18 479,-324.18 475.5,-334.18 482.5,-334.18"/>
|
||||||
|
</g>
|
||||||
|
<!-- n4 -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>n4</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="702" cy="-306" rx="112.38" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="702" y="-302.3" font-family="Times,serif" font-size="14.00">wasmer-compiler-singlepass</text>
|
||||||
|
</g>
|
||||||
|
<!-- n0->n4 -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>n0->n4</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M513.33,-372.82C533.27,-368.35 558.77,-362.1 581,-355 606.24,-346.94 633.75,-336.2 656.14,-326.91"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="657.53,-330.13 665.41,-323.04 654.83,-323.67 657.53,-330.13"/>
|
||||||
|
</g>
|
||||||
|
<!-- n1 -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>n1</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="590" cy="-162" rx="73.39" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="590" y="-158.3" font-family="Times,serif" font-size="14.00">wasmer-compiler</text>
|
||||||
|
</g>
|
||||||
|
<!-- n9 -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>n9</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="590" cy="-90" rx="53.09" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="590" y="-86.3" font-family="Times,serif" font-size="14.00">wasmer-vm</text>
|
||||||
|
</g>
|
||||||
|
<!-- n1->n9 -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>n1->n9</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M590,-143.7C590,-135.98 590,-126.71 590,-118.11"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="593.5,-118.1 590,-108.1 586.5,-118.1 593.5,-118.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- n5 -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>n5</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="287" cy="-234" rx="64.99" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="287" y="-230.3" font-family="Times,serif" font-size="14.00">wasmer-engine</text>
|
||||||
|
</g>
|
||||||
|
<!-- n5->n1 -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>n5->n1</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M335.35,-221.83C387.75,-209.72 471.52,-190.37 528.56,-177.19"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="529.58,-180.55 538.53,-174.89 528,-173.73 529.58,-180.55"/>
|
||||||
|
</g>
|
||||||
|
<!-- n6->n5 -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>n6->n5</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M287,-287.7C287,-279.98 287,-270.71 287,-262.11"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="290.5,-262.1 287,-252.1 283.5,-262.1 290.5,-262.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- n7->n5 -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>n7->n5</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M144.49,-289.81C172.98,-278.85 211.51,-264.03 241.33,-252.57"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="242.6,-255.83 250.68,-248.97 240.09,-249.29 242.6,-255.83"/>
|
||||||
|
</g>
|
||||||
|
<!-- n8 -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>n8</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="590" cy="-18" rx="59.59" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="590" y="-14.3" font-family="Times,serif" font-size="14.00">wasmer-types</text>
|
||||||
|
</g>
|
||||||
|
<!-- n9->n8 -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>n9->n8</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M590,-71.7C590,-63.98 590,-54.71 590,-46.11"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="593.5,-46.1 590,-36.1 586.5,-46.1 593.5,-46.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- n10 -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>n10</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="338" cy="-528" rx="59.29" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="338" y="-524.3" font-family="Times,serif" font-size="14.00">wasmer-c-api</text>
|
||||||
|
</g>
|
||||||
|
<!-- n11 -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>n11</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="479" cy="-453" rx="80.69" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="479" y="-449.3" font-family="Times,serif" font-size="14.00">wasmer-emscripten</text>
|
||||||
|
</g>
|
||||||
|
<!-- n10->n11 -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>n10->n11</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M368.64,-512.56C375.69,-509.16 383.13,-505.5 390,-502 407,-493.34 425.6,-483.38 441.39,-474.79"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="443.22,-477.77 450.32,-469.91 439.87,-471.63 443.22,-477.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- n12 -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>n12</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="323" cy="-453" rx="57.69" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="323" y="-449.3" font-family="Times,serif" font-size="14.00">wasmer-wasi</text>
|
||||||
|
</g>
|
||||||
|
<!-- n10->n12 -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>n10->n12</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M334.45,-509.7C332.69,-501.15 330.53,-490.65 328.56,-481.07"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="331.97,-480.27 326.53,-471.18 325.11,-481.68 331.97,-480.27"/>
|
||||||
|
</g>
|
||||||
|
<!-- n11->n0 -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>n11->n0</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M479,-434.7C479,-426.98 479,-417.71 479,-409.11"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="482.5,-409.1 479,-399.1 475.5,-409.1 482.5,-409.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- n12->n0 -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>n12->n0</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M354.57,-437.83C380.1,-426.38 416.07,-410.24 442.77,-398.26"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="444.46,-401.33 452.15,-394.05 441.6,-394.95 444.46,-401.33"/>
|
||||||
|
</g>
|
||||||
|
<!-- n13 -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>n13</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="639" cy="-453" rx="61.99" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="639" y="-449.3" font-family="Times,serif" font-size="14.00">wasmer-cache</text>
|
||||||
|
</g>
|
||||||
|
<!-- n13->n0 -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>n13->n0</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M606.24,-437.67C579.82,-426.11 542.7,-409.87 515.37,-397.91"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="516.71,-394.68 506.14,-393.87 513.9,-401.09 516.71,-394.68"/>
|
||||||
|
</g>
|
||||||
|
<!-- n14 -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>n14</title>
|
||||||
|
<ellipse fill="none" stroke="orange" cx="479" cy="-528" rx="50.09" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="479" y="-524.3" font-family="Times,serif" font-size="14.00">wasmer-cli</text>
|
||||||
|
</g>
|
||||||
|
<!-- n14->n11 -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>n14->n11</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M479,-509.7C479,-501.25 479,-490.87 479,-481.37"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="482.5,-481.18 479,-471.18 475.5,-481.18 482.5,-481.18"/>
|
||||||
|
</g>
|
||||||
|
<!-- n14->n12 -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>n14->n12</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M436.19,-518.44C420.87,-514.52 403.75,-509.12 389,-502 375.04,-495.26 360.95,-485.51 349.4,-476.55"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="351.47,-473.73 341.47,-470.23 347.11,-479.2 351.47,-473.73"/>
|
||||||
|
</g>
|
||||||
|
<!-- n14->n13 -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>n14->n13</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M522.27,-518.78C538.34,-514.85 556.44,-509.37 572,-502 586.15,-495.3 600.45,-485.56 612.18,-476.6"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="614.53,-479.2 620.23,-470.26 610.21,-473.7 614.53,-479.2"/>
|
||||||
|
</g>
|
||||||
|
<!-- n2->n1 -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>n2->n1</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M899.09,-289.12C834.21,-262.65 704.27,-209.63 635.35,-181.5"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="636.62,-178.24 626.04,-177.71 633.98,-184.72 636.62,-178.24"/>
|
||||||
|
</g>
|
||||||
|
<!-- n3->n1 -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>n3->n1</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M492.17,-288.15C511.61,-263.28 548.12,-216.57 570.62,-187.79"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="573.45,-189.86 576.85,-179.82 567.93,-185.55 573.45,-189.86"/>
|
||||||
|
</g>
|
||||||
|
<!-- n4->n1 -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>n4->n1</title>
|
||||||
|
<path fill="none" stroke="orange" stroke-dasharray="5,2" d="M688.49,-287.87C668.79,-262.9 632.08,-216.35 609.46,-187.68"/>
|
||||||
|
<polygon fill="orange" stroke="orange" points="612.15,-185.43 603.21,-179.75 606.65,-189.77 612.15,-185.43"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 12 KiB |
346
docs/migration_to_1.0.0.md
Normal file
346
docs/migration_to_1.0.0.md
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
# Migrating from Wasmer 0.x to Wasmer 1.0.0
|
||||||
|
|
||||||
|
Wasmer 1.0.0 is currently in alpha and is our primary focus. This document will
|
||||||
|
describe the differences between Wasmer 0.x and Wasmer 1.0.0 and provide examples
|
||||||
|
to make migrating to the new API as simple as possible.
|
||||||
|
|
||||||
|
Some features are still under development during the alpha of Wasmer 1.0.0. This document
|
||||||
|
will aim to make clear what these features are.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Rationale for changes in 1.0.0](#rationale-for-changes-in-100)
|
||||||
|
- [How to use Wasmer 1.0.0](#how-to-use-wasmer-100)
|
||||||
|
- [Installing Wasmer CLI](#installing-wamser-cli)
|
||||||
|
- [Using Wasmer 1.0.0](#using-wamser-100)
|
||||||
|
- [Project structure](#project-structure)
|
||||||
|
- [Differences](#differences)
|
||||||
|
- [Instantiating modules](#instantiating-modules)
|
||||||
|
- [Passing host functions](#passing-host-functions)
|
||||||
|
- [Accessing the environment as a host function](#accessing-the-environment-as-a-host-function)
|
||||||
|
- [Error handling](#error-handling)
|
||||||
|
- [Caching modules](#caching-modules)
|
||||||
|
|
||||||
|
## Rationale for changes in 1.0.0
|
||||||
|
|
||||||
|
Wasmer 0.x was great but as the WASM community and standards evolve we felt the need to make Wasmer also follow these
|
||||||
|
changes.
|
||||||
|
|
||||||
|
Wasmer 1.x is what we think a necessary rewrite of a big part of the project to make it more future-proof.
|
||||||
|
|
||||||
|
This version introduces many new features and makes using Wasmer more natural. We did a hard work making it as close
|
||||||
|
to the standard API as possible while always providing good performances, flexibility and stability.
|
||||||
|
|
||||||
|
The rewrite of the Wasmer Runtime also comes with a rewrite of the languages integrations to achieve the same goals:
|
||||||
|
providing a clearer API and improving the feature set.
|
||||||
|
|
||||||
|
In this document you will discover the major changes between Wasmer 0.x and Wasmer 1.x by highlighting how to use the
|
||||||
|
new Rust API.
|
||||||
|
|
||||||
|
## How to use Wasmer 1.0.0
|
||||||
|
|
||||||
|
### Installing Wasmer CLI
|
||||||
|
|
||||||
|
See [wasmer.io] for installation instructions.
|
||||||
|
|
||||||
|
If you already have wasmer installed, run `wasmer self-update`.
|
||||||
|
|
||||||
|
Install the latest versions of Wasmer with [wasmer-nightly] or by following the steps described in the
|
||||||
|
documentation: [Getting Started][getting-started].
|
||||||
|
|
||||||
|
### Using Wasmer 1.0.0
|
||||||
|
|
||||||
|
The CLI interface for Wasmer 1.0.0 is mostly the same as it was in Wasmer 0.x.
|
||||||
|
|
||||||
|
One difference is that rather than specifying the compiler with `--backend=cranelift`,
|
||||||
|
in Wasmer 1.0.0 we prefer using the name of the backend as a flag directly,
|
||||||
|
for example: `--cranelift`.
|
||||||
|
|
||||||
|
The top-level crates that users will usually interface with are:
|
||||||
|
|
||||||
|
- [wasmer] - Wasmer's core runtime API
|
||||||
|
- [wasmer-wasi] - Wasmer's WASI implementation
|
||||||
|
- [wasmer-emscripten] - Wasmer's Emscripten implementation
|
||||||
|
- TODO:
|
||||||
|
|
||||||
|
See the [examples] to find out how to do specific things in Wasmer 1.0.0.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The figure above shows the core Wasmer crates and their dependencies with transitive dependencies deduplicated.
|
||||||
|
|
||||||
|
Wasmer 1.0.0 has two core architectural abstractions: engines and compilers.
|
||||||
|
|
||||||
|
An engine is a system that processes WASM with a compiler and prepares it to be executed.
|
||||||
|
|
||||||
|
A compiler is a system that translates WASM into a format that can be understood
|
||||||
|
more directly by a real computer: machine code.
|
||||||
|
|
||||||
|
For example, in the [examples] you'll see that we are using the JIT engine and the Cranelift compiler. The JIT engine
|
||||||
|
will generate machine code at runtime, using Cranelift, and then execute it.
|
||||||
|
|
||||||
|
For most uses, users will primarily use the [wasmer] crate directly, perhaps with one of our
|
||||||
|
provided ABIs such as [wasmer-wasi]. However, for users that need finer grained control over
|
||||||
|
the behavior of wasmer, other crates such as [wasmer-compiler] and [wasmer-engine] may be used
|
||||||
|
to implement custom compilers and engines respectively.
|
||||||
|
|
||||||
|
## Differences
|
||||||
|
|
||||||
|
### Instantiating modules
|
||||||
|
|
||||||
|
With Wasmer 0.x, instantiating a module was a matter of calling `wasmer::compiler::compile` and then calling
|
||||||
|
`instanciate` on the compiled module.
|
||||||
|
|
||||||
|
While simple, this did not give you full-control over Wasmer's configuration. For example, choosing another compiler
|
||||||
|
was not straightforward.
|
||||||
|
|
||||||
|
With Wasmer 1.x, we changed this part and made the API look more like how Wasmer works internally to give you more
|
||||||
|
control:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- let module = compile(&wasm_bytes[..])?;
|
||||||
|
+ let engine = JIT::new(&Cranelift::default()).engine();
|
||||||
|
+ let store = Store::new(&engine);
|
||||||
|
+ let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
- let instance = module.instantiate(&imports)?;
|
||||||
|
+ let instance = Instance::new(&module, &import_object)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that we did not cover how to create the import object here. This is because this part works the same as it used to
|
||||||
|
with Wasmer 0.x.
|
||||||
|
|
||||||
|
To get more information on how instantiation now works, have a look at the [dedicated example][instance-example]
|
||||||
|
|
||||||
|
### Passing host functions
|
||||||
|
|
||||||
|
With Wasmer 0.x passing host functions to the guest was primarily done using the `func!` macro or by directly using
|
||||||
|
`Func::new` or `DynamicFunc::new`.
|
||||||
|
|
||||||
|
Given we have a function like:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn sum(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We want to import this function in the guest module, let's have a look at how it differs between Wasmer 0.x and
|
||||||
|
Wasmer 1.x:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
- "sum" => func!(sum),
|
||||||
|
+ "sum" => Function::new_native(&store, sum),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The above example illustrates how to import what we call "native functions". There were already available in Wasmer
|
||||||
|
0.x through the `func!` macro or with `Func::new`.
|
||||||
|
|
||||||
|
There is a second flavor for imported functions: dynamic functions. With Wasmer 0;x you would have created such a
|
||||||
|
function using `DynamicFunc::new`, here is how it's done with Wasmer 1.x:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let sum_signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
|
||||||
|
let sum = Function::new(&store, &sum_signature, |args| {
|
||||||
|
let result = args[0].unwrap_I32() + args[1].unwrap_i32();
|
||||||
|
|
||||||
|
Ok(vec![Value::I32(result)])
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Both examples address different needs and have their own pros and cons. We encourage you to have a look at the
|
||||||
|
dedicated example: [Exposing host functions][host-functions-example].
|
||||||
|
|
||||||
|
Note that having this API for functions now looks more like the other entities APIs: globals, memories, tables. Here is
|
||||||
|
a quick example introducing each of them: [Imports & Exports][imports-exports-example]
|
||||||
|
|
||||||
|
### Accessing the environment as a host function
|
||||||
|
|
||||||
|
With Wasmer 0.x each function had its own `vm::Ctx`. This was your entrypoint to the module internals and allowed
|
||||||
|
access to the context of the currently running instance.
|
||||||
|
|
||||||
|
With Wasmer 1.0.0 this was changed to provide a simpler yet powerful API.
|
||||||
|
|
||||||
|
Let's see an example where we want to have access to the module memory. Here is how we would have done that with Wasmer
|
||||||
|
0.x:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- let get_at = |ctx: &mut vm::Ctx, idx: i32, len: i32| {
|
||||||
|
- let mem_desc = ctx.memory(0);
|
||||||
|
- let mem = mem_desc.deref();
|
||||||
|
-
|
||||||
|
- println!("Memory: {:?}", mem);
|
||||||
|
-
|
||||||
|
- let view: MemoryView<u8> = mem.view();
|
||||||
|
- let bytes = view[idx as usize..len as usize].iter().map(Cell::get).collect();
|
||||||
|
-
|
||||||
|
- println!("string: {}", String::from_utf8(bytes).unwrap());
|
||||||
|
- };
|
||||||
|
|
||||||
|
- let import_object = imports! {
|
||||||
|
- "env" => {
|
||||||
|
- "get_at" => func!(get_at),
|
||||||
|
- }
|
||||||
|
- };
|
||||||
|
+ let import_object = imports! {};
|
||||||
|
|
||||||
|
- let instance = instantiate(wasm_bytes, &import_object)?;
|
||||||
|
+ let instance = Instance::new(&wasm_bytes, &import_object)?;
|
||||||
|
|
||||||
|
+ let memory = instance.exports.get_memory("mem")?;
|
||||||
|
+ let get = instance
|
||||||
|
+ .exports
|
||||||
|
+ .get_native_function::<(), (WasmPtr<u8, Array>, i32)>("get")?;
|
||||||
|
+ let (ptr, length) = get.call()?;
|
||||||
|
+ let str = ptr.get_utf8_string(memory, length as u32)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
Here we have a module which provides one exported function: `get`. Each time we call this function it will in turn
|
||||||
|
call our imported function `get_at`.
|
||||||
|
|
||||||
|
The `get_at` function is responsible for reading the guest module-s memory through the `vm::Ctx`.
|
||||||
|
|
||||||
|
With Wasmer 1.0.0 (where the `vm::Ctx` does not exist anymore) we can achieve the same result with something more
|
||||||
|
natural: we only use imports and exports to read from the memory and write to it.
|
||||||
|
|
||||||
|
Take a look at the following examples to get more details:
|
||||||
|
* [Interacting with memory][memory]
|
||||||
|
* [Using memory pointers][memory-pointers]
|
||||||
|
|
||||||
|
The other thing where `vm::Ctx` was useful was to pass data from and to host functions. This has also been made simpler
|
||||||
|
with Wasmer 1.x:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let shared_counter: Arc<RefCell<i32>> = Arc::new(RefCell::new(0));
|
||||||
|
|
||||||
|
struct Env {
|
||||||
|
counter: Arc<RefCell<i32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_counter(env: &mut Env) -> i32 {
|
||||||
|
*env.counter.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
let get_counter_func = Function::new_native_with_env(
|
||||||
|
&store,
|
||||||
|
Env { counter: shared_counter.clone() },
|
||||||
|
get_counter
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
A dedicated example describes how to use this feature: [Exposing host functions][host-functions].
|
||||||
|
|
||||||
|
### Error handling
|
||||||
|
|
||||||
|
Handling errors with Wasmer 0.x was a bit hard, especially, the `wasmer_runtime::error::RuntimeError`. It was rather
|
||||||
|
complex: it had many variants that you had to handle when pattern matching results. This has been made way simpler with
|
||||||
|
Wasmer 1.0.0:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
// Retrieve the `get` function from module's exports and then call it
|
||||||
|
let result = get.call(0, 13);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
- Err(RuntimeError::InvokeError(InvokeError::TrapCode { .. })) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::InvokeError(InvokeError::FailedWithNoError)) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::InvokeError(InvokeError::UnknownTrap { .. })) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::InvokeError(InvokeError::UnknownTrapCode { .. })) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::InvokeError(InvokeError::EarlyTrap(_))) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::InvokeError(InvokeError::Breakpoint(_))) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::Metering(_)) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::InstanceImage(_)) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
- Err(RuntimeError::User(_)) => {
|
||||||
|
- // ...
|
||||||
|
- }
|
||||||
|
+ Error(e) => {
|
||||||
|
+ println!("Error caught from `div_by_zero`: {}", e.message());
|
||||||
|
+
|
||||||
|
+ let frames = e.trace();
|
||||||
|
+ let frames_len = frames.len();
|
||||||
|
+
|
||||||
|
+ // ...
|
||||||
|
+ }
|
||||||
|
Ok(_) => {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see here, handling errors is really easy now! You may find the following examples useful to get more familiar
|
||||||
|
with this topic:
|
||||||
|
* [Handling Errors][errors]
|
||||||
|
* [Interrupting Execution][exit-early]
|
||||||
|
|
||||||
|
Note than with Wasmer 1.0.0, each function that is part of the API has its own kind of error. For example:
|
||||||
|
* Instantiating a module may return `InstantiationError`s;
|
||||||
|
* Getting exports from the guest module may return `ExportError`s;
|
||||||
|
* Calling a exported function may return `RuntimeError`s;
|
||||||
|
* ...
|
||||||
|
|
||||||
|
### Caching modules
|
||||||
|
|
||||||
|
You may be aware Wasmer, since 0.x, allows you to cache compiled module so that further executions of your program
|
||||||
|
will be faster.
|
||||||
|
|
||||||
|
Because caching may bring a significant boost when running Wasm modules we wanted to make it easier to use with
|
||||||
|
Wasmer 1.0.0.
|
||||||
|
|
||||||
|
With Wasmer 0.x you had to handle the whole caching process inside your program's code. With Wasmer 1.0.0
|
||||||
|
you'll be able to delegate most of the work to Wasmer:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- let artifact = module.cache().unwrap();
|
||||||
|
- let bytes = artifact.serialize().unwrap();
|
||||||
|
-
|
||||||
|
- let path = "module_cached.so";
|
||||||
|
- fs::write(path, bytes).unwrap();
|
||||||
|
+ module.serialize_to_file(path)?;
|
||||||
|
|
||||||
|
- let mut file = File::open(path).unwrap();
|
||||||
|
- let cached_bytes = &mut vec![];
|
||||||
|
- file.read_to_end(cached_bytes);
|
||||||
|
- drop(file);
|
||||||
|
-
|
||||||
|
- let cached_artifact = Artifact::deserialize(&cached_bytes).unwrap();
|
||||||
|
- let cached_module = unsafe { load_cache_with(cached_artifact, &default_compiler()) }.unwrap();
|
||||||
|
+ let cached_module = unsafe { Module::deserialize_from_file(&store, path) }?;
|
||||||
|
```
|
||||||
|
|
||||||
|
[examples]: https://docs.wasmer.io/integrations/examples
|
||||||
|
[wasmer]: https://crates.io/crates/wasmer/1.0.0-alpha3
|
||||||
|
[wasmer-wasi]: https://crates.io/crates/wasmer-wasi/1.0.0-alpha3
|
||||||
|
[wasmer-emscripten]: https://crates.io/crates/wasmer-emscripten/1.0.0-alpha3
|
||||||
|
[wasmer-engine]: https://crates.io/crates/wasmer-engine/1.0.0-alpha3
|
||||||
|
[wasmer-compiler]: https://crates.io/crates/wasmer-compiler/1.0.0-alpha3
|
||||||
|
[wasmer.io]: https://wasmer.io
|
||||||
|
[wasmer-nightly]: https://github.com/wasmerio/wasmer-nightly/
|
||||||
|
[getting-started]: https://docs.wasmer.io/ecosystem/wasmer/getting-started
|
||||||
|
[instance-example]: https://docs.wasmer.io/integrations/examples/instance
|
||||||
|
[imports-exports-example]: https://docs.wasmer.io/integrations/examples/imports-and-exports
|
||||||
|
[host-functions-example]: https://docs.wasmer.io/integrations/examples/host-functions
|
||||||
|
[memory]: https://docs.wasmer.io/integrations/examples/memory
|
||||||
|
[memory-pointers]: https://docs.wasmer.io/integrations/examples/memory-pointers
|
||||||
|
[host-functions]: https://docs.wasmer.io/integrations/examples/host-functions
|
||||||
|
[errors]: https://docs.wasmer.io/integrations/examples/errors
|
||||||
|
[exit-early]: https://docs.wasmer.io/integrations/examples/exit-early
|
||||||
@@ -37,6 +37,173 @@ The examples are written in a difficulty/discovery order. Concepts that
|
|||||||
are explained in an example is not necessarily re-explained in a next
|
are explained in an example is not necessarily re-explained in a next
|
||||||
example.
|
example.
|
||||||
|
|
||||||
|
### Basics
|
||||||
|
|
||||||
|
1. [**Instantiating a module**][instance], explains the basics of using Wasmer
|
||||||
|
and how to create an instance out of a Wasm module.
|
||||||
|
|
||||||
|
_Keywords_: instance, module.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example instance --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
2. [**Handling errors**][errors], explains the basics of interacting with
|
||||||
|
Wasm module memory.
|
||||||
|
|
||||||
|
_Keywords_: memory, module.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example memory --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
3. [**Interacting with memory**][memory], explains the basics of interacting with
|
||||||
|
Wasm module memory.
|
||||||
|
|
||||||
|
_Keywords_: memory, module.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example memory --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Exports
|
||||||
|
|
||||||
|
1. [**Exported global**][exported-global], explains how to work with
|
||||||
|
exported globals: get/set their value, have information about their
|
||||||
|
type.
|
||||||
|
|
||||||
|
_Keywords_: export, global.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example exported-globals --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
2. [**Exported function**][exported-function], explains how to get and
|
||||||
|
how to call an exported function. They come in 2 flavors: dynamic,
|
||||||
|
and “static”/native. The pros and cons are discussed briefly.
|
||||||
|
|
||||||
|
_Keywords_: export, function, dynamic, static, native.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example exported-function --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
3. [**Exported memory**][exported-memory], explains how to read from
|
||||||
|
and write to exported memory.
|
||||||
|
|
||||||
|
_Keywords_: export, memory.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example exported-memory --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Imports
|
||||||
|
|
||||||
|
1. [**Imported global**][imported-global], explains how to work with
|
||||||
|
imported globals: create globals, import them, get/set their value.
|
||||||
|
|
||||||
|
_Keywords_: import, global.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example imported-globals --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
2. [**Imported function**][imported-function], explains how to define
|
||||||
|
an imported function. They come in 2 flavors: dynamic,
|
||||||
|
and “static”/native.
|
||||||
|
|
||||||
|
_Keywords_: import, function, dynamic, static, native.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example imported-function --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Externs
|
||||||
|
|
||||||
|
1. [**Table**][table], explains how to use Wasm Tables from the Wasmer API.
|
||||||
|
|
||||||
|
_Keywords_: basic, table, call_indirect
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example table --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
2. [**Memory**][memory], explains how to use Wasm Memories from
|
||||||
|
the Wasmer API. Memory example is a work in progress.
|
||||||
|
|
||||||
|
_Keywords_: basic, memory
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example memory --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Tunables
|
||||||
|
|
||||||
|
1. **Limit memory**, explains how to use Tunables to limit the
|
||||||
|
size of an exported Wasm memory
|
||||||
|
|
||||||
|
_Keywords_: basic, tunables, memory
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><em>Execute the example</em></summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ cargo run --example tunables-limit-memory --release --features "cranelift"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
### Engines
|
### Engines
|
||||||
|
|
||||||
1. [**JIT engine**][engine-jit], explains what an engine is, what the
|
1. [**JIT engine**][engine-jit], explains what an engine is, what the
|
||||||
@@ -107,7 +274,7 @@ example.
|
|||||||
|
|
||||||
### Compilers
|
### Compilers
|
||||||
|
|
||||||
5. [**Singlepass compiler**][compiler-singlepass], explains how to use
|
1. [**Singlepass compiler**][compiler-singlepass], explains how to use
|
||||||
the [`wasmer-compiler-singlepass`] compiler.
|
the [`wasmer-compiler-singlepass`] compiler.
|
||||||
|
|
||||||
_Keywords_: compiler, singlepass.
|
_Keywords_: compiler, singlepass.
|
||||||
@@ -121,7 +288,7 @@ example.
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
6. [**Cranelift compiler**][compiler-cranelift], explains how to use
|
2. [**Cranelift compiler**][compiler-cranelift], explains how to use
|
||||||
the [`wasmer-compiler-cranelift`] compiler.
|
the [`wasmer-compiler-cranelift`] compiler.
|
||||||
|
|
||||||
_Keywords_: compiler, cranelift.
|
_Keywords_: compiler, cranelift.
|
||||||
@@ -135,7 +302,7 @@ example.
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
7. [**LLVM compiler**][compiler-llvm], explains how to use the
|
3. [**LLVM compiler**][compiler-llvm], explains how to use the
|
||||||
[`wasmer-compiler-llvm`] compiler.
|
[`wasmer-compiler-llvm`] compiler.
|
||||||
|
|
||||||
_Keywords_: compiler, llvm.
|
_Keywords_: compiler, llvm.
|
||||||
@@ -149,116 +316,9 @@ example.
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Exports
|
|
||||||
|
|
||||||
8. [**Exported global**][exported-global], explains how to work with
|
|
||||||
exported globals: get/set their value, have information about their
|
|
||||||
type.
|
|
||||||
|
|
||||||
_Keywords_: export, global.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example exported-globals --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
9. [**Exported function**][exported-function], explains how to get and
|
|
||||||
how to call an exported function. They come in 2 flavors: dynamic,
|
|
||||||
and “static”/native. The pros and cons are discussed briefly.
|
|
||||||
|
|
||||||
_Keywords_: export, function, dynamic, static, native.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example exported-function --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
10. [**Exported memory**][exported-memory], explains how to read from
|
|
||||||
and write to exported memory.
|
|
||||||
|
|
||||||
_Keywords_: export, memory.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example exported-memory --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Imports
|
|
||||||
|
|
||||||
11. [**Imported global**][imported-global], explains how to work with
|
|
||||||
imported globals: create globals, import them, get/set their value.
|
|
||||||
|
|
||||||
_Keywords_: import, global.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example imported-globals --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
12. [**Imported function**][imported-function], explains how to define
|
|
||||||
an imported function. They come in 2 flavors: dynamic,
|
|
||||||
and “static”/native.
|
|
||||||
|
|
||||||
_Keywords_: import, function, dynamic, static, native.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example imported-function --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Externs
|
|
||||||
|
|
||||||
13. [**Table**][table], explains how to use Wasm Tables from the Wasmer API.
|
|
||||||
|
|
||||||
_Keywords_: basic, table, call_indirect
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example table --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
14. [**Memory**][memory], explains how to use Wasm Memories from
|
|
||||||
the Wasmer API. Memory example is a work in progress.
|
|
||||||
|
|
||||||
_Keywords_: basic, memory
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><em>Execute the example</em></summary>
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo run --example memory --release --features "cranelift"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Integrations
|
### Integrations
|
||||||
|
|
||||||
15. [**WASI**][wasi], explains how to use the [WebAssembly System
|
1. [**WASI**][wasi], explains how to use the [WebAssembly System
|
||||||
Interface][WASI] (WASI), i.e. the [`wasmer-wasi`] crate.
|
Interface][WASI] (WASI), i.e. the [`wasmer-wasi`] crate.
|
||||||
|
|
||||||
_Keywords_: wasi, system, interface
|
_Keywords_: wasi, system, interface
|
||||||
@@ -284,6 +344,7 @@ example.
|
|||||||
[exported-memory]: ./exports_memory.rs
|
[exported-memory]: ./exports_memory.rs
|
||||||
[imported-global]: ./imports_global.rs
|
[imported-global]: ./imports_global.rs
|
||||||
[imported-function]: ./imports_function.rs
|
[imported-function]: ./imports_function.rs
|
||||||
|
[instance]: ./instance.rs
|
||||||
[wasi]: ./wasi.rs
|
[wasi]: ./wasi.rs
|
||||||
[table]: ./table.rs
|
[table]: ./table.rs
|
||||||
[memory]: ./memory.rs
|
[memory]: ./memory.rs
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
//! This example shows how the host can terminate execution of Wasm early from
|
//! There are cases where you may want to interrupt this synchronous execution of the WASM module
|
||||||
//! inside a host function called by the Wasm.
|
//! while the it is calling a host function. This can be useful for saving resources, and not
|
||||||
|
//! returning back to the guest WASM for execution, when you already know the WASM execution will
|
||||||
|
//! fail, or no longer be needed.
|
||||||
|
//!
|
||||||
|
//! In this example, we will run a WASM module that calls the imported host function
|
||||||
|
//! interrupt_execution. This host function will immediately stop executing the WebAssembly module.
|
||||||
|
//!
|
||||||
|
//! You can run the example directly by executing in Wasmer root:
|
||||||
|
//!
|
||||||
|
//! ```shell
|
||||||
|
//! cargo run --example early-exit --release --features "cranelift"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Ready?
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -21,12 +34,6 @@ impl fmt::Display for ExitCode {
|
|||||||
// And then we implement `std::error::Error`.
|
// And then we implement `std::error::Error`.
|
||||||
impl std::error::Error for ExitCode {}
|
impl std::error::Error for ExitCode {}
|
||||||
|
|
||||||
// The host function that we'll use to terminate execution.
|
|
||||||
fn early_exit() {
|
|
||||||
// This is where it happens.
|
|
||||||
RuntimeError::raise(Box::new(ExitCode(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
// Let's declare the Wasm module with the text representation.
|
// Let's declare the Wasm module with the text representation.
|
||||||
let wasm_bytes = wat2wasm(
|
let wasm_bytes = wat2wasm(
|
||||||
@@ -44,21 +51,40 @@ fn main() -> anyhow::Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Create a Store.
|
||||||
|
// Note that we don't need to specify the engine/compiler if we want to use
|
||||||
|
// the default provided by Wasmer.
|
||||||
|
// You can use `Store::default()` for that.
|
||||||
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
||||||
|
|
||||||
|
println!("Compiling module...");
|
||||||
|
// Let's compile the Wasm module.
|
||||||
let module = Module::new(&store, wasm_bytes)?;
|
let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
|
||||||
|
// We declare the host function that we'll use to terminate execution.
|
||||||
|
fn early_exit() {
|
||||||
|
// This is where it happens.
|
||||||
|
RuntimeError::raise(Box::new(ExitCode(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an import object.
|
||||||
let import_object = imports! {
|
let import_object = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
"early_exit" => Function::new_native(&store, early_exit),
|
"early_exit" => Function::new_native(&store, early_exit),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("Instantiating module...");
|
||||||
|
// Let's instantiate the Wasm module.
|
||||||
let instance = Instance::new(&module, &import_object)?;
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
|
||||||
|
// Here we go.
|
||||||
|
//
|
||||||
// Get the `run` function which we'll use as our entrypoint.
|
// Get the `run` function which we'll use as our entrypoint.
|
||||||
let run_func: NativeFunc<(i32, i32), i32> =
|
println!("Calling `run` function...");
|
||||||
instance.exports.get_native_function("run").unwrap();
|
let run_func: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("run")?;
|
||||||
|
|
||||||
// When we call a function it can either succeed or fail.
|
// When we call a function it can either succeed or fail. We expect it to fail.
|
||||||
match run_func.call(1, 7) {
|
match run_func.call(1, 7) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
bail!(
|
bail!(
|
||||||
@@ -66,12 +92,13 @@ fn main() -> anyhow::Result<()> {
|
|||||||
result
|
result
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// We're expecting it to fail.
|
// In case of a failure, which we expect, we attempt to downcast the error into the error
|
||||||
// We attempt to downcast the error into the error type that we were expecting.
|
// type that we were expecting.
|
||||||
Err(e) => match e.downcast::<ExitCode>() {
|
Err(e) => match e.downcast::<ExitCode>() {
|
||||||
// We found the exit code used to terminate execution.
|
// We found the exit code used to terminate execution.
|
||||||
Ok(exit_code) => {
|
Ok(exit_code) => {
|
||||||
println!("Exited early with exit code: {}", exit_code);
|
println!("Exited early with exit code: {}", exit_code);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
103
examples/errors.rs
Normal file
103
examples/errors.rs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
//! A Wasm module can sometimes be invalid or trigger traps, and in those case we will get
|
||||||
|
//! an error back from the API.
|
||||||
|
//!
|
||||||
|
//! In this example we'll see how to handle such errors in the most
|
||||||
|
//! basic way. To do that we'll use a Wasm module that we know will
|
||||||
|
//! produce an error.
|
||||||
|
//!
|
||||||
|
//! You can run the example directly by executing in Wasmer root:
|
||||||
|
//!
|
||||||
|
//! ```shell
|
||||||
|
//! cargo run --example errors --release --features "cranelift"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Ready?
|
||||||
|
|
||||||
|
use wasmer::{imports, wat2wasm, Instance, Module, Store};
|
||||||
|
use wasmer_compiler_cranelift::Cranelift;
|
||||||
|
use wasmer_engine_jit::JIT;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Let's declare the Wasm module with the text representation.
|
||||||
|
let wasm_bytes = wat2wasm(
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(type $do_div_by_zero_t (func (result i32)))
|
||||||
|
(func $do_div_by_zero_f (type $do_div_by_zero_t) (result i32)
|
||||||
|
i32.const 4
|
||||||
|
i32.const 0
|
||||||
|
i32.div_s)
|
||||||
|
|
||||||
|
(type $div_by_zero_t (func (result i32)))
|
||||||
|
(func $div_by_zero_f (type $div_by_zero_t) (result i32)
|
||||||
|
call $do_div_by_zero_f)
|
||||||
|
(export "div_by_zero" (func $div_by_zero_f)))
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Create a Store.
|
||||||
|
// Note that we don't need to specify the engine/compiler if we want to use
|
||||||
|
// the default provided by Wasmer.
|
||||||
|
// You can use `Store::default()` for that.
|
||||||
|
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
||||||
|
|
||||||
|
println!("Compiling module...");
|
||||||
|
// Let's compile the Wasm module.
|
||||||
|
let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
|
||||||
|
// Create an import object.
|
||||||
|
let import_object = imports! {};
|
||||||
|
|
||||||
|
println!("Instantiating module...");
|
||||||
|
// Let's instantiate the Wasm module.
|
||||||
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
|
||||||
|
// Here we go.
|
||||||
|
//
|
||||||
|
// The Wasm module exports a function called `div_by_zero`. As its name
|
||||||
|
// implies, this function will try to do a division by zero and thus
|
||||||
|
// produce an error.
|
||||||
|
//
|
||||||
|
// Let's get it.
|
||||||
|
let div_by_zero = instance
|
||||||
|
.exports
|
||||||
|
.get_function("div_by_zero")?
|
||||||
|
.native::<(), i32>()?;
|
||||||
|
|
||||||
|
println!("Calling `div_by_zero` function...");
|
||||||
|
// Let's call the `div_by_zero` exported function.
|
||||||
|
let result = div_by_zero.call();
|
||||||
|
|
||||||
|
// When we call a function it can either succeed or fail. We expect it to fail.
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
// This should have thrown an error, return an error
|
||||||
|
panic!("div_by_zero did not error");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Log the error
|
||||||
|
println!("Error caught from `div_by_zero`: {}", e.message());
|
||||||
|
|
||||||
|
// Errors come with a trace we can inspect to get more
|
||||||
|
// information on the execution flow.
|
||||||
|
let frames = e.trace();
|
||||||
|
let frames_len = frames.len();
|
||||||
|
|
||||||
|
for i in 0..frames_len {
|
||||||
|
println!(
|
||||||
|
" Frame #{}: {:?}::{:?}",
|
||||||
|
frames_len - i,
|
||||||
|
frames[i].module_name(),
|
||||||
|
frames[i].function_name().or(Some("<func>")).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exported_function() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
main()
|
||||||
|
}
|
||||||
@@ -72,10 +72,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
println!("Calling `sum` function...");
|
println!("Calling `sum` function...");
|
||||||
// Let's call the `sum` exported function. The parameters are a
|
// Let's call the `sum` exported function. The parameters are a
|
||||||
// slice of `Value`s. The results are a boxed slice of `Value`s.
|
// slice of `Value`s. The results are a boxed slice of `Value`s.
|
||||||
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
|
let args = [Value::I32(1), Value::I32(2)];
|
||||||
|
let result = sum.call(&args)?;
|
||||||
|
|
||||||
println!("Results: {:?}", results);
|
println!("Results: {:?}", result);
|
||||||
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
|
assert_eq!(result.to_vec(), vec![Value::I32(3)]);
|
||||||
|
|
||||||
// That was fun. But what if we can get rid of the `Value`s? Well,
|
// That was fun. But what if we can get rid of the `Value`s? Well,
|
||||||
// that's possible with the `NativeFunction` API. The function
|
// that's possible with the `NativeFunction` API. The function
|
||||||
@@ -85,16 +86,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// `Rets`, respectively for the parameters and the results. If
|
// `Rets`, respectively for the parameters and the results. If
|
||||||
// those values don't match the exported function signature, an
|
// those values don't match the exported function signature, an
|
||||||
// error will be raised.
|
// error will be raised.
|
||||||
let sum = sum.native::<(i32, i32), i32>()?;
|
let sum_native = sum.native::<(i32, i32), i32>()?;
|
||||||
|
|
||||||
println!("Calling `sum` function (natively)...");
|
println!("Calling `sum` function (natively)...");
|
||||||
// Let's call the `sum` exported function. The parameters are
|
// Let's call the `sum` exported function. The parameters are
|
||||||
// statically typed Rust values of type `i32` and `i32`. The
|
// statically typed Rust values of type `i32` and `i32`. The
|
||||||
// result, in this case particular case, in a unit of type `i32`.
|
// result, in this case particular case, in a unit of type `i32`.
|
||||||
let result = sum.call(1, 2)?;
|
let result = sum_native.call(3, 4)?;
|
||||||
|
|
||||||
println!("Results: {:?}", result);
|
println!("Results: {:?}", result);
|
||||||
assert_eq!(result, 3);
|
assert_eq!(result, 7);
|
||||||
|
|
||||||
// Much nicer, isn't it?
|
// Much nicer, isn't it?
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -68,16 +68,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let one = instance.exports.get_global("one")?;
|
let one = instance.exports.get_global("one")?;
|
||||||
let some = instance.exports.get_global("some")?;
|
let some = instance.exports.get_global("some")?;
|
||||||
|
|
||||||
println!("Getting global type informations...");
|
println!("Getting globals types information...");
|
||||||
// Let's get the globals types. The results are `GlobalType`s.
|
// Let's get the globals types. The results are `GlobalType`s.
|
||||||
let one_type = one.ty();
|
let one_type = one.ty();
|
||||||
let some_type = some.ty();
|
let some_type = some.ty();
|
||||||
|
|
||||||
println!("one type: {:?} {:?}", one_type.mutability, one_type.ty);
|
println!("`one` type: {:?} {:?}", one_type.mutability, one_type.ty);
|
||||||
assert_eq!(one_type.mutability, Mutability::Const);
|
assert_eq!(one_type.mutability, Mutability::Const);
|
||||||
assert_eq!(one_type.ty, Type::F32);
|
assert_eq!(one_type.ty, Type::F32);
|
||||||
|
|
||||||
println!("some type: {:?} {:?}", some_type.mutability, some_type.ty);
|
println!("`some` type: {:?} {:?}", some_type.mutability, some_type.ty);
|
||||||
assert_eq!(some_type.mutability, Mutability::Var);
|
assert_eq!(some_type.mutability, Mutability::Var);
|
||||||
assert_eq!(some_type.ty, Type::F32);
|
assert_eq!(some_type.ty, Type::F32);
|
||||||
|
|
||||||
@@ -93,14 +93,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.get_function("get_one")?
|
.get_function("get_one")?
|
||||||
.native::<(), f32>()?;
|
.native::<(), f32>()?;
|
||||||
|
|
||||||
let one_result = get_one.call()?;
|
let one_value = get_one.call()?;
|
||||||
let some_result = some.get();
|
let some_value = some.get();
|
||||||
|
|
||||||
println!("one value: {:?}", one_result);
|
println!("`one` value: {:?}", one_value);
|
||||||
assert_eq!(one_result, 1.0);
|
assert_eq!(one_value, 1.0);
|
||||||
|
|
||||||
println!("some value: {:?}", some_result);
|
println!("`some` value: {:?}", some_value);
|
||||||
assert_eq!(some_result, Value::F32(0.0));
|
assert_eq!(some_value, Value::F32(0.0));
|
||||||
|
|
||||||
println!("Setting global values...");
|
println!("Setting global values...");
|
||||||
// Trying to set the value of a immutable global (`const`)
|
// Trying to set the value of a immutable global (`const`)
|
||||||
@@ -112,7 +112,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let one_result = one.get();
|
let one_result = one.get();
|
||||||
println!("one value after `set`: {:?}", one_result);
|
println!("`one` value after `set`: {:?}", one_result);
|
||||||
assert_eq!(one_result, Value::F32(1.0));
|
assert_eq!(one_result, Value::F32(1.0));
|
||||||
|
|
||||||
// Setting the values of globals can be done in two ways:
|
// Setting the values of globals can be done in two ways:
|
||||||
@@ -126,12 +126,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.native::<f32, ()>()?;
|
.native::<f32, ()>()?;
|
||||||
set_some.call(21.0)?;
|
set_some.call(21.0)?;
|
||||||
let some_result = some.get();
|
let some_result = some.get();
|
||||||
println!("some value after `set_some`: {:?}", some_result);
|
println!("`some` value after `set_some`: {:?}", some_result);
|
||||||
assert_eq!(some_result, Value::F32(21.0));
|
assert_eq!(some_result, Value::F32(21.0));
|
||||||
|
|
||||||
some.set(Value::F32(42.0))?;
|
some.set(Value::F32(42.0))?;
|
||||||
let some_result = some.get();
|
let some_result = some.get();
|
||||||
println!("some value after `set`: {:?}", some_result);
|
println!("`some` value after `set`: {:?}", some_result);
|
||||||
assert_eq!(some_result, Value::F32(42.0));
|
assert_eq!(some_result, Value::F32(42.0));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
let multiply_native = Function::new_native(&store, multiply);
|
let multiply_native = Function::new_native(&store, multiply);
|
||||||
|
|
||||||
// Create an empty import object.
|
// Create an import object.
|
||||||
let import_object = imports! {
|
let import_object = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
"multiply_dynamic" => multiply_dynamic,
|
"multiply_dynamic" => multiply_dynamic,
|
||||||
|
|||||||
129
examples/imports_function_env.rs
Normal file
129
examples/imports_function_env.rs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
//! A Wasm module can import entities, like functions, memories,
|
||||||
|
//! globals and tables.
|
||||||
|
//!
|
||||||
|
//! In this example, we'll create a system for getting and adjusting a counter value. However, host
|
||||||
|
//! functions are not limited to storing data outside of WASM, they're normal host functions and
|
||||||
|
//! can do anything that the host can do.
|
||||||
|
//!
|
||||||
|
//! 1. There will be a `get_counter` function that will return an i32 of
|
||||||
|
//! the current global counter,
|
||||||
|
//! 2. There will be an `add_to_counter` function will add the passed
|
||||||
|
//! i32 value to the counter, and return an i32 of the current
|
||||||
|
//! global counter.
|
||||||
|
//!
|
||||||
|
//! You can run the example directly by executing in Wasmer root:
|
||||||
|
//!
|
||||||
|
//! ```shell
|
||||||
|
//! cargo run --example imported-function-env --release --features "cranelift"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Ready?
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wasmer::{imports, wat2wasm, Function, Instance, Module, Store};
|
||||||
|
use wasmer_compiler_cranelift::Cranelift;
|
||||||
|
use wasmer_engine_jit::JIT;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Let's declare the Wasm module with the text representation.
|
||||||
|
let wasm_bytes = wat2wasm(
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $get_counter (import "env" "get_counter") (result i32))
|
||||||
|
(func $add_to_counter (import "env" "add_to_counter") (param i32) (result i32))
|
||||||
|
|
||||||
|
(type $increment_t (func (param i32) (result i32)))
|
||||||
|
(func $increment_f (type $increment_t) (param $x i32) (result i32)
|
||||||
|
(block
|
||||||
|
(loop
|
||||||
|
(call $add_to_counter (i32.const 1))
|
||||||
|
(set_local $x (i32.sub (get_local $x) (i32.const 1)))
|
||||||
|
(br_if 1 (i32.eq (get_local $x) (i32.const 0)))
|
||||||
|
(br 0)))
|
||||||
|
call $get_counter)
|
||||||
|
(export "increment_counter_loop" (func $increment_f)))
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Create a Store.
|
||||||
|
// Note that we don't need to specify the engine/compiler if we want to use
|
||||||
|
// the default provided by Wasmer.
|
||||||
|
// You can use `Store::default()` for that.
|
||||||
|
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
||||||
|
|
||||||
|
println!("Compiling module...");
|
||||||
|
// Let's compile the Wasm module.
|
||||||
|
let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
|
||||||
|
// We create some shared data here, `Arc` is required because we may
|
||||||
|
// move our WebAssembly instance to another thread to run it. RefCell
|
||||||
|
// lets us get shared mutabilty which is fine because we know we won't
|
||||||
|
// run host calls concurrently. If concurrency is a possibilty, we'd have
|
||||||
|
// to use a `Mutex`.
|
||||||
|
let shared_counter: Arc<RefCell<i32>> = Arc::new(RefCell::new(0));
|
||||||
|
|
||||||
|
// Once we have our counter we'll wrap it inside en `Env` which we'll pass
|
||||||
|
// to our imported functions.
|
||||||
|
//
|
||||||
|
// This struct may have been anything. The only constraint is it must be
|
||||||
|
// possible to know the size of the `Env` at compile time (i.e it has to
|
||||||
|
// implement the `Sized` trait).
|
||||||
|
struct Env {
|
||||||
|
counter: Arc<RefCell<i32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the functions
|
||||||
|
fn get_counter(env: &mut Env) -> i32 {
|
||||||
|
*env.counter.borrow()
|
||||||
|
}
|
||||||
|
fn add_to_counter(env: &mut Env, add: i32) -> i32 {
|
||||||
|
let mut counter_ref = env.counter.borrow_mut();
|
||||||
|
|
||||||
|
*counter_ref += add;
|
||||||
|
*counter_ref
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an import object.
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"get_counter" => Function::new_native_with_env(&store, Env { counter: shared_counter.clone() }, get_counter),
|
||||||
|
"add_to_counter" => Function::new_native_with_env(&store, Env { counter: shared_counter.clone() }, add_to_counter),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Instantiating module...");
|
||||||
|
// Let's instantiate the Wasm module.
|
||||||
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
|
||||||
|
// Here we go.
|
||||||
|
//
|
||||||
|
// The Wasm module exports a function called `increment_counter_loop`. Let's get it.
|
||||||
|
let increment_counter_loop = instance
|
||||||
|
.exports
|
||||||
|
.get_function("increment_counter_loop")?
|
||||||
|
.native::<i32, i32>()?;
|
||||||
|
|
||||||
|
let counter_value: i32 = *shared_counter.borrow();
|
||||||
|
println!("Initial ounter value: {:?}", counter_value);
|
||||||
|
|
||||||
|
println!("Calling `increment_counter_loop` function...");
|
||||||
|
// Let's call the `increment_counter_loop` exported function.
|
||||||
|
//
|
||||||
|
// It will loop five times thus incrementing our counter five times.
|
||||||
|
let result = increment_counter_loop.call(5)?;
|
||||||
|
|
||||||
|
let counter_value: i32 = *shared_counter.borrow();
|
||||||
|
println!("New counter value (host): {:?}", counter_value);
|
||||||
|
assert_eq!(counter_value, 5);
|
||||||
|
|
||||||
|
println!("New counter value (guest): {:?}", counter_value);
|
||||||
|
assert_eq!(result, 5);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_imported_function_env() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
main()
|
||||||
|
}
|
||||||
80
examples/instance.rs
Normal file
80
examples/instance.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
//! Wasmer will let you easily run Wasm module in a Rust host.
|
||||||
|
//!
|
||||||
|
//! This example illustrates the basics of using Wasmer through a "Hello World"-like project:
|
||||||
|
//!
|
||||||
|
//! 1. How to load a Wasm modules as bytes
|
||||||
|
//! 2. How to compile the module
|
||||||
|
//! 3. How to create an instance of the module
|
||||||
|
//!
|
||||||
|
//! You can run the example directly by executing in Wasmer root:
|
||||||
|
//!
|
||||||
|
//! ```shell
|
||||||
|
//! cargo run --example instance --release --features "cranelift"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Ready?
|
||||||
|
|
||||||
|
use wasmer::{imports, wat2wasm, Instance, Module, Store};
|
||||||
|
use wasmer_compiler_cranelift::Cranelift;
|
||||||
|
use wasmer_engine_jit::JIT;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Let's declare the Wasm module.
|
||||||
|
//
|
||||||
|
// We are using the text representation of the module here but you can also load `.wasm`
|
||||||
|
// files using the `include_bytes!` macro.
|
||||||
|
let wasm_bytes = wat2wasm(
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(type $add_one_t (func (param i32) (result i32)))
|
||||||
|
(func $add_one_f (type $add_one_t) (param $value i32) (result i32)
|
||||||
|
local.get $value
|
||||||
|
i32.const 1
|
||||||
|
i32.add)
|
||||||
|
(export "add_one" (func $add_one_f)))
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Create a Store.
|
||||||
|
// Note that we don't need to specify the engine/compiler if we want to use
|
||||||
|
// the default provided by Wasmer.
|
||||||
|
// You can use `Store::default()` for that.
|
||||||
|
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
||||||
|
|
||||||
|
println!("Compiling module...");
|
||||||
|
// Let's compile the Wasm module.
|
||||||
|
let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
|
||||||
|
// Create an empty import object.
|
||||||
|
let import_object = imports! {};
|
||||||
|
|
||||||
|
println!("Instantiating module...");
|
||||||
|
// Let's instantiate the Wasm module.
|
||||||
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
|
||||||
|
// We now have an instance ready to be used.
|
||||||
|
//
|
||||||
|
// From an `Instance` we can retrieve any exported entities.
|
||||||
|
// Each of these entities is covered in others examples.
|
||||||
|
//
|
||||||
|
// Here we are retrieving the exported function. We won't go into details here
|
||||||
|
// as the main focus of this example is to show how to create an instance out
|
||||||
|
// of a Wasm module and have basic interactions with it.
|
||||||
|
let add_one = instance
|
||||||
|
.exports
|
||||||
|
.get_function("add_one")?
|
||||||
|
.native::<i32, i32>()?;
|
||||||
|
|
||||||
|
println!("Calling `add_one` function...");
|
||||||
|
let result = add_one.call(1)?;
|
||||||
|
|
||||||
|
println!("Results of `add_one`: {:?}", result);
|
||||||
|
assert_eq!(result, 2);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exported_function() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
main()
|
||||||
|
}
|
||||||
@@ -1,7 +1,21 @@
|
|||||||
use wasmer::{
|
//! With Wasmer you'll be able to interact with guest module memory.
|
||||||
imports, wat2wasm, Extern, Function, Instance, Memory, MemoryType, Module, NativeFunc, Pages,
|
//!
|
||||||
Store, Table, TableType, Type, Value,
|
//! This example illustrates the basics of interacting with Wasm module memory.:
|
||||||
};
|
//!
|
||||||
|
//! 1. How to load a Wasm modules as bytes
|
||||||
|
//! 2. How to compile the module
|
||||||
|
//! 3. How to create an instance of the module
|
||||||
|
//!
|
||||||
|
//! You can run the example directly by executing in Wasmer root:
|
||||||
|
//!
|
||||||
|
//! ```shell
|
||||||
|
//! cargo run --example memory --release --features "cranelift"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Ready?
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use wasmer::{imports, wat2wasm, Bytes, Instance, Module, NativeFunc, Pages, Store};
|
||||||
use wasmer_compiler_cranelift::Cranelift;
|
use wasmer_compiler_cranelift::Cranelift;
|
||||||
use wasmer_engine_jit::JIT;
|
use wasmer_engine_jit::JIT;
|
||||||
|
|
||||||
@@ -9,6 +23,10 @@ use wasmer_engine_jit::JIT;
|
|||||||
// TODO: clean it up and comment it https://github.com/wasmerio/wasmer/issues/1749
|
// TODO: clean it up and comment it https://github.com/wasmerio/wasmer/issues/1749
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
// Let's declare the Wasm module.
|
||||||
|
//
|
||||||
|
// We are using the text representation of the module here but you can also load `.wasm`
|
||||||
|
// files using the `include_bytes!` macro.
|
||||||
let wasm_bytes = wat2wasm(
|
let wasm_bytes = wat2wasm(
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
@@ -35,47 +53,87 @@ fn main() -> anyhow::Result<()> {
|
|||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// We set up our store with an engine and a compiler.
|
// Create a Store.
|
||||||
|
// Note that we don't need to specify the engine/compiler if we want to use
|
||||||
|
// the default provided by Wasmer.
|
||||||
|
// You can use `Store::default()` for that.
|
||||||
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
|
||||||
// Then compile our Wasm.
|
|
||||||
|
println!("Compiling module...");
|
||||||
|
// Let's compile the Wasm module.
|
||||||
let module = Module::new(&store, wasm_bytes)?;
|
let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
|
||||||
|
// Create an empty import object.
|
||||||
let import_object = imports! {};
|
let import_object = imports! {};
|
||||||
// And instantiate it with no imports.
|
|
||||||
|
println!("Instantiating module...");
|
||||||
|
// Let's instantiate the Wasm module.
|
||||||
let instance = Instance::new(&module, &import_object)?;
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
|
||||||
|
// The module exports some utility functions, let's get them.
|
||||||
|
//
|
||||||
|
// These function will be used later in this example.
|
||||||
let mem_size: NativeFunc<(), i32> = instance.exports.get_native_function("mem_size")?;
|
let mem_size: NativeFunc<(), i32> = instance.exports.get_native_function("mem_size")?;
|
||||||
let get_at: NativeFunc<i32, i32> = instance.exports.get_native_function("get_at")?;
|
let get_at: NativeFunc<i32, i32> = instance.exports.get_native_function("get_at")?;
|
||||||
let set_at: NativeFunc<(i32, i32), ()> = instance.exports.get_native_function("set_at")?;
|
let set_at: NativeFunc<(i32, i32), ()> = instance.exports.get_native_function("set_at")?;
|
||||||
let memory = instance.exports.get_memory("memory")?;
|
let memory = instance.exports.get_memory("memory")?;
|
||||||
|
|
||||||
let mem_addr = 0x2220;
|
// We now have an instance ready to be used.
|
||||||
let val = 0xFEFEFFE;
|
//
|
||||||
|
// We will start by querying the most intersting information
|
||||||
|
// about the memory: its size. There are mainly two ways of getting
|
||||||
|
// this:
|
||||||
|
// * the size as a number of `Page`s
|
||||||
|
// * the size as a number of bytes
|
||||||
|
//
|
||||||
|
// The size in bytes can be found either by querying its pages or by
|
||||||
|
// querying the memory directly.
|
||||||
|
println!("Querying memory size...");
|
||||||
assert_eq!(memory.size(), Pages::from(1));
|
assert_eq!(memory.size(), Pages::from(1));
|
||||||
|
assert_eq!(memory.size().bytes(), Bytes::from(65536 as usize));
|
||||||
|
assert_eq!(memory.data_size(), 65536);
|
||||||
|
|
||||||
|
// Sometimes, the guest module may also export a function to let you
|
||||||
|
// query the memory. Here we have a `mem_size` function, let's try it:
|
||||||
|
let result = mem_size.call()?;
|
||||||
|
println!("Memory size: {:?}", result);
|
||||||
|
assert_eq!(Pages::from(result as u32), memory.size());
|
||||||
|
|
||||||
|
// Now that we know the size of our memory, it's time to see how wa
|
||||||
|
// can change this.
|
||||||
|
//
|
||||||
|
// A memory can be grown to allow storing more things into it. Let's
|
||||||
|
// see how we can do that:
|
||||||
|
println!("Growing memory...");
|
||||||
|
// Here we are requesting two more pages for our memory.
|
||||||
memory.grow(2)?;
|
memory.grow(2)?;
|
||||||
assert_eq!(memory.size(), Pages::from(3));
|
assert_eq!(memory.size(), Pages::from(3));
|
||||||
let result = mem_size.call()?;
|
assert_eq!(memory.data_size(), 65536 * 3);
|
||||||
assert_eq!(result, 3);
|
|
||||||
|
|
||||||
// -------------
|
// Now that we know how to query and adjust the size of the memory,
|
||||||
|
// let's see how wa can write to it or read from it.
|
||||||
|
//
|
||||||
|
// We'll only focus on how to do this using exported functions, the goal
|
||||||
|
// is to show how to work with memory addresses. Here we'll use absolute
|
||||||
|
// addresses to write and read a value.
|
||||||
|
let mem_addr = 0x2220;
|
||||||
|
let val = 0xFEFEFFE;
|
||||||
set_at.call(mem_addr, val)?;
|
set_at.call(mem_addr, val)?;
|
||||||
// -------------
|
|
||||||
|
|
||||||
let page_size = 0x1_0000;
|
|
||||||
let result = get_at.call(page_size * 3 - 4)?;
|
|
||||||
memory.grow(1025)?;
|
|
||||||
assert_eq!(memory.size(), Pages::from(1028));
|
|
||||||
set_at.call(page_size * 1027 - 4, 123456)?;
|
|
||||||
let result = get_at.call(page_size * 1027 - 4)?;
|
|
||||||
assert_eq!(result, 123456);
|
|
||||||
set_at.call(1024, 123456)?;
|
|
||||||
let result = get_at.call(1024)?;
|
|
||||||
assert_eq!(result, 123456);
|
|
||||||
|
|
||||||
// -------------
|
|
||||||
let result = get_at.call(mem_addr)?;
|
let result = get_at.call(mem_addr)?;
|
||||||
|
println!("Value at {:#x?}: {:?}", mem_addr, result);
|
||||||
|
assert_eq!(result, val);
|
||||||
|
|
||||||
|
// Now instead of using hard coded memory addresses, let's try to write
|
||||||
|
// something at the end of the second memory page and read it.
|
||||||
|
let page_size = 0x1_0000;
|
||||||
|
let mem_addr = (page_size * 2) - mem::size_of_val(&val) as i32;
|
||||||
|
let val = 0xFEA09;
|
||||||
|
set_at.call(mem_addr, val)?;
|
||||||
|
|
||||||
|
let result = get_at.call(mem_addr)?;
|
||||||
|
println!("Value at {:#x?}: {:?}", mem_addr, result);
|
||||||
assert_eq!(result, val);
|
assert_eq!(result, val);
|
||||||
// -------------
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
184
examples/tunables_limit_memory.rs
Normal file
184
examples/tunables_limit_memory.rs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
use std::ptr::NonNull;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use wasmer::{
|
||||||
|
imports,
|
||||||
|
vm::{self, MemoryError, MemoryStyle, TableStyle, VMMemoryDefinition, VMTableDefinition},
|
||||||
|
wat2wasm, Instance, Memory, MemoryType, Module, Pages, Store, TableType, Target,
|
||||||
|
Tunables as ReferenceTunables,
|
||||||
|
};
|
||||||
|
use wasmer_compiler_cranelift::Cranelift;
|
||||||
|
use wasmer_engine::Tunables;
|
||||||
|
use wasmer_engine_jit::JIT;
|
||||||
|
|
||||||
|
/// A custom tunables that allows you to set a memory limit.
|
||||||
|
///
|
||||||
|
/// After adjusting the memory limits, it delegates all other logic
|
||||||
|
/// to the base tunables.
|
||||||
|
pub struct LimitingTunables<T: Tunables> {
|
||||||
|
/// The maximum a linear memory is allowed to be (in Wasm pages, 64 KiB each).
|
||||||
|
/// Since Wasmer ensures there is only none or one memory, this is practically
|
||||||
|
/// an upper limit for the guest memory.
|
||||||
|
limit: Pages,
|
||||||
|
/// The base implementation we delegate all the logic to
|
||||||
|
base: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Tunables> LimitingTunables<T> {
|
||||||
|
pub fn new(base: T, limit: Pages) -> Self {
|
||||||
|
Self { limit, base }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes in input memory type as requested by the guest and sets
|
||||||
|
/// a maximum if missing. The resulting memory type is final if
|
||||||
|
/// valid. However, this can produce invalid types, such that
|
||||||
|
/// validate_memory must be called before creating the memory.
|
||||||
|
fn adjust_memory(&self, requested: &MemoryType) -> MemoryType {
|
||||||
|
let mut adjusted = requested.clone();
|
||||||
|
if requested.maximum.is_none() {
|
||||||
|
adjusted.maximum = Some(self.limit);
|
||||||
|
}
|
||||||
|
adjusted
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures the a given memory type does not exceed the memory limit.
|
||||||
|
/// Call this after adjusting the memory.
|
||||||
|
fn validate_memory(&self, ty: &MemoryType) -> Result<(), MemoryError> {
|
||||||
|
if ty.minimum > self.limit {
|
||||||
|
return Err(MemoryError::Generic(
|
||||||
|
"Minimum exceeds the allowed memory limit".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(max) = ty.maximum {
|
||||||
|
if max > self.limit {
|
||||||
|
return Err(MemoryError::Generic(
|
||||||
|
"Maximum exceeds the allowed memory limit".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(MemoryError::Generic("Maximum unset".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Tunables> Tunables for LimitingTunables<T> {
|
||||||
|
/// Construct a `MemoryStyle` for the provided `MemoryType`
|
||||||
|
///
|
||||||
|
/// Delegated to base.
|
||||||
|
fn memory_style(&self, memory: &MemoryType) -> MemoryStyle {
|
||||||
|
let adjusted = self.adjust_memory(memory);
|
||||||
|
self.base.memory_style(&adjusted)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a `TableStyle` for the provided `TableType`
|
||||||
|
///
|
||||||
|
/// Delegated to base.
|
||||||
|
fn table_style(&self, table: &TableType) -> TableStyle {
|
||||||
|
self.base.table_style(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`].
|
||||||
|
///
|
||||||
|
/// The requested memory type is validated, adjusted to the limited and then passed to base.
|
||||||
|
fn create_host_memory(
|
||||||
|
&self,
|
||||||
|
ty: &MemoryType,
|
||||||
|
style: &MemoryStyle,
|
||||||
|
) -> Result<Arc<dyn vm::Memory>, MemoryError> {
|
||||||
|
let adjusted = self.adjust_memory(ty);
|
||||||
|
self.validate_memory(&adjusted)?;
|
||||||
|
self.base.create_host_memory(&adjusted, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`].
|
||||||
|
///
|
||||||
|
/// Delegated to base.
|
||||||
|
unsafe fn create_vm_memory(
|
||||||
|
&self,
|
||||||
|
ty: &MemoryType,
|
||||||
|
style: &MemoryStyle,
|
||||||
|
vm_definition_location: NonNull<VMMemoryDefinition>,
|
||||||
|
) -> Result<Arc<dyn vm::Memory>, MemoryError> {
|
||||||
|
let adjusted = self.adjust_memory(ty);
|
||||||
|
self.validate_memory(&adjusted)?;
|
||||||
|
self.base
|
||||||
|
.create_vm_memory(&adjusted, style, vm_definition_location)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a table owned by the host given a [`TableType`] and a [`TableStyle`].
|
||||||
|
///
|
||||||
|
/// Delegated to base.
|
||||||
|
fn create_host_table(
|
||||||
|
&self,
|
||||||
|
ty: &TableType,
|
||||||
|
style: &TableStyle,
|
||||||
|
) -> Result<Arc<dyn vm::Table>, String> {
|
||||||
|
self.base.create_host_table(ty, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`].
|
||||||
|
///
|
||||||
|
/// Delegated to base.
|
||||||
|
unsafe fn create_vm_table(
|
||||||
|
&self,
|
||||||
|
ty: &TableType,
|
||||||
|
style: &TableStyle,
|
||||||
|
vm_definition_location: NonNull<VMTableDefinition>,
|
||||||
|
) -> Result<Arc<dyn vm::Table>, String> {
|
||||||
|
self.base.create_vm_table(ty, style, vm_definition_location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// A Wasm module with one exported memory (min: 7 pages, max: unset)
|
||||||
|
let wat = br#"(module (memory 7) (export "memory" (memory 0)))"#;
|
||||||
|
|
||||||
|
// Alternatively: A Wasm module with one exported memory (min: 7 pages, max: 80 pages)
|
||||||
|
// let wat = br#"(module (memory 7 80) (export "memory" (memory 0)))"#;
|
||||||
|
|
||||||
|
let wasm_bytes = wat2wasm(wat)?;
|
||||||
|
|
||||||
|
// Any compiler and any engine do the job here
|
||||||
|
let compiler = Cranelift::default();
|
||||||
|
let engine = JIT::new(&compiler).engine();
|
||||||
|
|
||||||
|
// Here is where the fun begins
|
||||||
|
|
||||||
|
let base = ReferenceTunables::for_target(&Target::default());
|
||||||
|
let tunables = LimitingTunables::new(base, Pages(24));
|
||||||
|
|
||||||
|
// Create a store, that holds the engine and our custom tunables
|
||||||
|
let store = Store::new_with_tunables(&engine, tunables);
|
||||||
|
|
||||||
|
println!("Compiling module...");
|
||||||
|
let module = Module::new(&store, wasm_bytes)?;
|
||||||
|
|
||||||
|
println!("Instantiating module...");
|
||||||
|
let import_object = imports! {};
|
||||||
|
|
||||||
|
// Now at this point, our custom tunables are used
|
||||||
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
|
||||||
|
// Check what happened
|
||||||
|
let mut memories: Vec<Memory> = instance
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.memories()
|
||||||
|
.map(|pair| pair.1.clone())
|
||||||
|
.collect();
|
||||||
|
assert_eq!(memories.len(), 1);
|
||||||
|
|
||||||
|
let first_memory = memories.pop().unwrap();
|
||||||
|
println!("Memory of this instance: {:?}", first_memory);
|
||||||
|
assert_eq!(first_memory.ty().maximum.unwrap(), Pages(24));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tunables_limit_memory() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
main()
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer"
|
name = "wasmer"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "High-performant WebAssembly runtime"
|
description = "High-performant WebAssembly runtime"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "runtime", "vm"]
|
keywords = ["wasm", "webassembly", "runtime", "vm"]
|
||||||
@@ -11,29 +11,29 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0-alpha4", optional = true }
|
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "1.0.0-alpha4", optional = true }
|
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "1.0.0-alpha4", optional = true }
|
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
|
||||||
wasmer-derive = { path = "../derive", version = "1.0.0-alpha4" }
|
wasmer-derive = { path = "../derive", version = "1.0.0-alpha5" }
|
||||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
|
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
|
||||||
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha4", optional = true }
|
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha4", optional = true }
|
wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
indexmap = { version = "1.4", features = ["serde-1"] }
|
indexmap = { version = "1.4", features = ["serde-1"] }
|
||||||
cfg-if = "0.1"
|
cfg-if = "0.1"
|
||||||
wat = { version = "1.0", optional = true }
|
wat = { version = "1.0", optional = true }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
more-asserts = "0.2"
|
more-asserts = "0.2"
|
||||||
target-lexicon = { version = "0.10", default-features = false }
|
target-lexicon = { version = "0.11", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = "0.3"
|
winapi = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# for the binary wasmer.rs
|
# for the binary wasmer.rs
|
||||||
libc = { version = "^0.2.69", default-features = false }
|
libc = { version = "^0.2", default-features = false }
|
||||||
wat = "1.0"
|
wat = "1.0"
|
||||||
tempfile = "3.1"
|
tempfile = "3.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|||||||
20
lib/api/src/externals/function.rs
vendored
20
lib/api/src/externals/function.rs
vendored
@@ -12,8 +12,8 @@ use std::cmp::max;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use wasmer_vm::{
|
use wasmer_vm::{
|
||||||
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction,
|
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction,
|
||||||
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
|
VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment,
|
||||||
VMTrampoline,
|
VMFunctionKind, VMTrampoline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A function defined in the Wasm module
|
/// A function defined in the Wasm module
|
||||||
@@ -86,7 +86,9 @@ impl Function {
|
|||||||
// The engine linker will replace the address with one pointing to a
|
// The engine linker will replace the address with one pointing to a
|
||||||
// generated dynamic trampoline.
|
// generated dynamic trampoline.
|
||||||
let address = std::ptr::null() as *const VMFunctionBody;
|
let address = std::ptr::null() as *const VMFunctionBody;
|
||||||
let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext;
|
let vmctx = VMFunctionEnvironment {
|
||||||
|
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
@@ -138,7 +140,9 @@ impl Function {
|
|||||||
// The engine linker will replace the address with one pointing to a
|
// The engine linker will replace the address with one pointing to a
|
||||||
// generated dynamic trampoline.
|
// generated dynamic trampoline.
|
||||||
let address = std::ptr::null() as *const VMFunctionBody;
|
let address = std::ptr::null() as *const VMFunctionBody;
|
||||||
let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext;
|
let vmctx = VMFunctionEnvironment {
|
||||||
|
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
|
||||||
|
};
|
||||||
// TODO: look into removing transmute by changing API type signatures
|
// TODO: look into removing transmute by changing API type signatures
|
||||||
let function_ptr = Some(unsafe {
|
let function_ptr = Some(unsafe {
|
||||||
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish)
|
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish)
|
||||||
@@ -184,7 +188,9 @@ impl Function {
|
|||||||
{
|
{
|
||||||
let function = inner::Function::<Args, Rets>::new(func);
|
let function = inner::Function::<Args, Rets>::new(func);
|
||||||
let address = function.address() as *const VMFunctionBody;
|
let address = function.address() as *const VMFunctionBody;
|
||||||
let vmctx = std::ptr::null_mut() as *mut VMContext;
|
let vmctx = VMFunctionEnvironment {
|
||||||
|
host_env: std::ptr::null_mut() as *mut _,
|
||||||
|
};
|
||||||
let signature = function.ty();
|
let signature = function.ty();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@@ -242,7 +248,9 @@ impl Function {
|
|||||||
// In the case of Host-defined functions `VMContext` is whatever environment
|
// In the case of Host-defined functions `VMContext` is whatever environment
|
||||||
// the user want to attach to the function.
|
// the user want to attach to the function.
|
||||||
let box_env = Box::new(env);
|
let box_env = Box::new(env);
|
||||||
let vmctx = Box::into_raw(box_env) as *mut VMContext;
|
let vmctx = VMFunctionEnvironment {
|
||||||
|
host_env: Box::into_raw(box_env) as *mut _,
|
||||||
|
};
|
||||||
// TODO: look into removing transmute by changing API type signatures
|
// TODO: look into removing transmute by changing API type signatures
|
||||||
let function_ptr = Some(unsafe {
|
let function_ptr = Some(unsafe {
|
||||||
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish)
|
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish)
|
||||||
|
|||||||
15
lib/api/src/externals/memory.rs
vendored
15
lib/api/src/externals/memory.rs
vendored
@@ -87,21 +87,26 @@ impl Memory {
|
|||||||
&self.store
|
&self.store
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: document this function.
|
/// Retrieve a slice of the memory contents.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// To be defined (TODO).
|
/// Until the returned slice is dropped, it is undefined behaviour to
|
||||||
|
/// modify the memory contents in any way including by calling a wasm
|
||||||
|
/// function that writes to the memory or by resizing the memory.
|
||||||
pub unsafe fn data_unchecked(&self) -> &[u8] {
|
pub unsafe fn data_unchecked(&self) -> &[u8] {
|
||||||
self.data_unchecked_mut()
|
self.data_unchecked_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: document this function, it's trivial to cause UB/break soundness with this
|
/// Retrieve a mutable slice of the memory contents.
|
||||||
/// method.
|
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// To be defined (TODO).
|
/// This method provides interior mutability without an UnsafeCell. Until
|
||||||
|
/// the returned value is dropped, it is undefined behaviour to read or
|
||||||
|
/// write to the pointed-to memory in any way except through this slice,
|
||||||
|
/// including by calling a wasm function that reads the memory contents or
|
||||||
|
/// by resizing this Memory.
|
||||||
#[allow(clippy::mut_from_ref)]
|
#[allow(clippy::mut_from_ref)]
|
||||||
pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
|
pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
|
||||||
let definition = self.memory.vmmemory();
|
let definition = self.memory.vmmemory();
|
||||||
|
|||||||
@@ -83,7 +83,17 @@ pub use wasmer_types::{
|
|||||||
Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
|
Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
|
||||||
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: should those be moved into wasmer::vm as well?
|
||||||
pub use wasmer_vm::{raise_user_trap, Export, MemoryError};
|
pub use wasmer_vm::{raise_user_trap, Export, MemoryError};
|
||||||
|
pub mod vm {
|
||||||
|
//! We use the vm module for re-exporting wasmer-vm types
|
||||||
|
|
||||||
|
pub use wasmer_vm::{
|
||||||
|
Memory, MemoryError, MemoryStyle, Table, TableStyle, VMMemoryDefinition, VMTableDefinition,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wat")]
|
#[cfg(feature = "wat")]
|
||||||
pub use wat::parse_bytes as wat2wasm;
|
pub use wat::parse_bytes as wat2wasm;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, W
|
|||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
use wasmer_types::NativeWasmType;
|
use wasmer_types::NativeWasmType;
|
||||||
use wasmer_vm::{
|
use wasmer_vm::{
|
||||||
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
|
ExportFunction, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A WebAssembly function that can be called natively
|
/// A WebAssembly function that can be called natively
|
||||||
@@ -26,7 +26,7 @@ pub struct NativeFunc<Args = (), Rets = ()> {
|
|||||||
definition: FunctionDefinition,
|
definition: FunctionDefinition,
|
||||||
store: Store,
|
store: Store,
|
||||||
address: *const VMFunctionBody,
|
address: *const VMFunctionBody,
|
||||||
vmctx: *mut VMContext,
|
vmctx: VMFunctionEnvironment,
|
||||||
arg_kind: VMFunctionKind,
|
arg_kind: VMFunctionKind,
|
||||||
// exported: ExportFunction,
|
// exported: ExportFunction,
|
||||||
_phantom: PhantomData<(Args, Rets)>,
|
_phantom: PhantomData<(Args, Rets)>,
|
||||||
@@ -42,7 +42,7 @@ where
|
|||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
store: Store,
|
store: Store,
|
||||||
address: *const VMFunctionBody,
|
address: *const VMFunctionBody,
|
||||||
vmctx: *mut VMContext,
|
vmctx: VMFunctionEnvironment,
|
||||||
arg_kind: VMFunctionKind,
|
arg_kind: VMFunctionKind,
|
||||||
definition: FunctionDefinition,
|
definition: FunctionDefinition,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -169,7 +169,7 @@ macro_rules! impl_native_traits {
|
|||||||
match self.arg_kind {
|
match self.arg_kind {
|
||||||
VMFunctionKind::Static => {
|
VMFunctionKind::Static => {
|
||||||
let results = catch_unwind(AssertUnwindSafe(|| unsafe {
|
let results = catch_unwind(AssertUnwindSafe(|| unsafe {
|
||||||
let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address);
|
let f = std::mem::transmute::<_, unsafe extern "C" fn( VMFunctionEnvironment, $( $x, )*) -> Rets::CStruct>(self.address);
|
||||||
// We always pass the vmctx
|
// We always pass the vmctx
|
||||||
f( self.vmctx, $( $x, )* )
|
f( self.vmctx, $( $x, )* )
|
||||||
})).map_err(|e| RuntimeError::new(format!("{:?}", e)))?;
|
})).map_err(|e| RuntimeError::new(format!("{:?}", e)))?;
|
||||||
@@ -179,12 +179,16 @@ macro_rules! impl_native_traits {
|
|||||||
let params_list = [ $( $x.to_native().to_value() ),* ];
|
let params_list = [ $( $x.to_native().to_value() ),* ];
|
||||||
let results = if !has_env {
|
let results = if !has_env {
|
||||||
type VMContextWithoutEnv = VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv>;
|
type VMContextWithoutEnv = VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv>;
|
||||||
let ctx = self.vmctx as *mut VMContextWithoutEnv;
|
unsafe {
|
||||||
unsafe { (*ctx).ctx.call(¶ms_list)? }
|
let ctx = self.vmctx.host_env as *mut VMContextWithoutEnv;
|
||||||
|
(*ctx).ctx.call(¶ms_list)?
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
type VMContextWithEnv = VMDynamicFunctionContext<VMDynamicFunctionWithEnv<std::ffi::c_void>>;
|
type VMContextWithEnv = VMDynamicFunctionContext<VMDynamicFunctionWithEnv<std::ffi::c_void>>;
|
||||||
let ctx = self.vmctx as *mut VMContextWithEnv;
|
unsafe {
|
||||||
unsafe { (*ctx).ctx.call(¶ms_list)? }
|
let ctx = self.vmctx.host_env as *mut VMContextWithEnv;
|
||||||
|
(*ctx).ctx.call(¶ms_list)?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let mut rets_list_array = Rets::empty_array();
|
let mut rets_list_array = Rets::empty_array();
|
||||||
let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128;
|
let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128;
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ impl BaseTunables for Tunables {
|
|||||||
let maximum = memory.maximum.unwrap_or_else(Pages::max_value);
|
let maximum = memory.maximum.unwrap_or_else(Pages::max_value);
|
||||||
if maximum <= self.static_memory_bound {
|
if maximum <= self.static_memory_bound {
|
||||||
MemoryStyle::Static {
|
MemoryStyle::Static {
|
||||||
|
// Bound can be larger than the maximum for performance reasons
|
||||||
bound: self.static_memory_bound,
|
bound: self.static_memory_bound,
|
||||||
offset_guard_size: self.static_memory_offset_guard_size,
|
offset_guard_size: self.static_memory_offset_guard_size,
|
||||||
}
|
}
|
||||||
@@ -140,3 +141,47 @@ impl BaseTunables for Tunables {
|
|||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memory_style() {
|
||||||
|
let tunables = Tunables {
|
||||||
|
static_memory_bound: Pages(2048),
|
||||||
|
static_memory_offset_guard_size: 128,
|
||||||
|
dynamic_memory_offset_guard_size: 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
// No maximum
|
||||||
|
let requested = MemoryType::new(3, None, true);
|
||||||
|
let style = tunables.memory_style(&requested);
|
||||||
|
match style {
|
||||||
|
MemoryStyle::Dynamic { offset_guard_size } => assert_eq!(offset_guard_size, 256),
|
||||||
|
s => panic!("Unexpected memory style: {:?}", s),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Large maximum
|
||||||
|
let requested = MemoryType::new(3, Some(5_000_000), true);
|
||||||
|
let style = tunables.memory_style(&requested);
|
||||||
|
match style {
|
||||||
|
MemoryStyle::Dynamic { offset_guard_size } => assert_eq!(offset_guard_size, 256),
|
||||||
|
s => panic!("Unexpected memory style: {:?}", s),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small maximum
|
||||||
|
let requested = MemoryType::new(3, Some(16), true);
|
||||||
|
let style = tunables.memory_style(&requested);
|
||||||
|
match style {
|
||||||
|
MemoryStyle::Static {
|
||||||
|
bound,
|
||||||
|
offset_guard_size,
|
||||||
|
} => {
|
||||||
|
assert_eq!(bound, Pages(2048));
|
||||||
|
assert_eq!(offset_guard_size, 128);
|
||||||
|
}
|
||||||
|
s => panic!("Unexpected memory style: {:?}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ impl ValFuncRef for Val {
|
|||||||
Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc {
|
Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc {
|
||||||
func_ptr: ptr::null(),
|
func_ptr: ptr::null(),
|
||||||
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
||||||
vmctx: ptr::null_mut(),
|
vmctx: wasmer_vm::VMFunctionEnvironment {
|
||||||
|
host_env: ptr::null_mut(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Self::FuncRef(f) => f.checked_anyfunc(),
|
Self::FuncRef(f) => f.checked_anyfunc(),
|
||||||
_ => return Err(RuntimeError::new("val is not funcref")),
|
_ => return Err(RuntimeError::new("val is not funcref")),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-c-api"
|
name = "wasmer-c-api"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer C API library"
|
description = "Wasmer C API library"
|
||||||
categories = ["wasm", "api-bindings"]
|
categories = ["wasm", "api-bindings"]
|
||||||
keywords = ["wasm", "webassembly", "runtime"]
|
keywords = ["wasm", "webassembly", "runtime"]
|
||||||
@@ -15,21 +15,21 @@ edition = "2018"
|
|||||||
crate-type = ["cdylib", "rlib", "staticlib"]
|
crate-type = ["cdylib", "rlib", "staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer = { version = "1.0.0-alpha4", path = "../api", default-features = false }
|
wasmer = { version = "1.0.0-alpha5", path = "../api", default-features = false }
|
||||||
wasmer-compiler = { version = "1.0.0-alpha4", path = "../compiler" }
|
wasmer-compiler = { version = "1.0.0-alpha5", path = "../compiler" }
|
||||||
wasmer-compiler-cranelift = { version = "1.0.0-alpha4", path = "../compiler-cranelift", optional = true }
|
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "../compiler-cranelift", optional = true }
|
||||||
wasmer-compiler-singlepass = { version = "1.0.0-alpha4", path = "../compiler-singlepass", optional = true }
|
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "../compiler-singlepass", optional = true }
|
||||||
wasmer-compiler-llvm = { version = "1.0.0-alpha4", path = "../compiler-llvm", optional = true }
|
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "../compiler-llvm", optional = true }
|
||||||
wasmer-emscripten = { version = "1.0.0-alpha4", path = "../emscripten", optional = true }
|
wasmer-emscripten = { version = "1.0.0-alpha5", path = "../emscripten", optional = true }
|
||||||
wasmer-engine = { version = "1.0.0-alpha4", path = "../engine" }
|
wasmer-engine = { version = "1.0.0-alpha5", path = "../engine" }
|
||||||
wasmer-engine-jit = { version = "1.0.0-alpha4", path = "../engine-jit", optional = true }
|
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "../engine-jit", optional = true }
|
||||||
wasmer-engine-native = { version = "1.0.0-alpha4", path = "../engine-native", optional = true }
|
wasmer-engine-native = { version = "1.0.0-alpha5", path = "../engine-native", optional = true }
|
||||||
wasmer-engine-object-file = { version = "1.0.0-alpha4", path = "../engine-object-file", optional = true }
|
wasmer-engine-object-file = { version = "1.0.0-alpha5", path = "../engine-object-file", optional = true }
|
||||||
wasmer-wasi = { version = "1.0.0-alpha4", path = "../wasi", optional = true }
|
wasmer-wasi = { version = "1.0.0-alpha5", path = "../wasi", optional = true }
|
||||||
wasmer-types = { version = "1.0.0-alpha4", path = "../wasmer-types" }
|
wasmer-types = { version = "1.0.0-alpha5", path = "../wasmer-types" }
|
||||||
cfg-if = "0.1"
|
cfg-if = "1.0"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = { version = "^0.2.69", default-features = false }
|
libc = { version = "^0.2", default-features = false }
|
||||||
libffi = { version = "0.9" }
|
libffi = { version = "0.9" }
|
||||||
serde = { version = "1", optional = true, features = ["derive"] }
|
serde = { version = "1", optional = true, features = ["derive"] }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
@@ -37,7 +37,10 @@ typetag = { version = "0.1", optional = true }
|
|||||||
paste = "0.1"
|
paste = "0.1"
|
||||||
# for generating code in the same way thot the wasm-c-api does
|
# for generating code in the same way thot the wasm-c-api does
|
||||||
# Commented out for now until we can find a solution to the exported function problem
|
# Commented out for now until we can find a solution to the exported function problem
|
||||||
# wasmer-wasm-c-api = { version = "1.0.0-alpha4", path = "crates/wasm-c-api" }
|
# wasmer-wasm-c-api = { version = "1.0.0-alpha5", path = "crates/wasm-c-api" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
inline-c = "0.1.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = [
|
||||||
@@ -89,4 +92,4 @@ cranelift-backend = ["cranelift"]
|
|||||||
llvm-backend = ["llvm"]
|
llvm-backend = ["llvm"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen = "0.15"
|
cbindgen = "0.15"
|
||||||
@@ -61,6 +61,7 @@ fn main() {
|
|||||||
|
|
||||||
build_wasm_c_api_headers(&crate_dir, &out_dir);
|
build_wasm_c_api_headers(&crate_dir, &out_dir);
|
||||||
build_wasmer_headers(&crate_dir, &out_dir);
|
build_wasmer_headers(&crate_dir, &out_dir);
|
||||||
|
build_inline_c_env_vars();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the header files for the `wasm_c_api` API.
|
/// Build the header files for the `wasm_c_api` API.
|
||||||
@@ -389,3 +390,44 @@ fn exclude_items_from_wasm_c_api(builder: Builder) -> Builder {
|
|||||||
.exclude_item("wasmer_engine_t")
|
.exclude_item("wasmer_engine_t")
|
||||||
.exclude_item("wat2wasm")
|
.exclude_item("wat2wasm")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_inline_c_env_vars() {
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
let mut shared_object_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
|
||||||
|
assert_eq!(shared_object_dir.file_name(), Some(OsStr::new("c-api")));
|
||||||
|
shared_object_dir.pop();
|
||||||
|
|
||||||
|
assert_eq!(shared_object_dir.file_name(), Some(OsStr::new("lib")));
|
||||||
|
shared_object_dir.pop();
|
||||||
|
|
||||||
|
shared_object_dir.push("target");
|
||||||
|
shared_object_dir.push(env::var("PROFILE").unwrap());
|
||||||
|
|
||||||
|
let shared_object_dir = shared_object_dir.as_path().to_string_lossy();
|
||||||
|
let include_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
|
||||||
|
// The following options mean:
|
||||||
|
//
|
||||||
|
// * `-I`, add `include_dir` to include search path,
|
||||||
|
// * `-L`, add `shared_object_dir` to library search path,
|
||||||
|
// * `-D_DEBUG`, enable debug mode to enable `assert.h`.
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-env=INLINE_C_RS_CFLAGS=-I{I} -L{L} -D_DEBUG",
|
||||||
|
I = include_dir,
|
||||||
|
L = shared_object_dir.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-env=INLINE_C_RS_LDFLAGS={shared_object_dir}/{lib}",
|
||||||
|
shared_object_dir = shared_object_dir,
|
||||||
|
lib = if cfg!(target_os = "windows") {
|
||||||
|
"wasmer_c_api.dll".to_string()
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
"libwasmer_c_api.dylib".to_string()
|
||||||
|
} else {
|
||||||
|
"libwasmer_c_api.so".to_string()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
0
lib/c-api/doc/wasm_c_api/.empty
Normal file
0
lib/c-api/doc/wasm_c_api/.empty
Normal file
132
lib/c-api/src/wasm_c_api/DEVELOPMENT.md
Normal file
132
lib/c-api/src/wasm_c_api/DEVELOPMENT.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Development Notes
|
||||||
|
|
||||||
|
## Ownerships
|
||||||
|
|
||||||
|
The [`wasm.h`] header thankfully defines the [`own`] “annotation”. It
|
||||||
|
specifies _who_ owns _what_. For example, in the following code:
|
||||||
|
|
||||||
|
```c
|
||||||
|
WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new(
|
||||||
|
own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*);
|
||||||
|
```
|
||||||
|
|
||||||
|
We must read that `wasm_importtype_new` takes the ownership of all its
|
||||||
|
three arguments. This function is then responsible to free those
|
||||||
|
data. We must also read that the returned value is owned by the caller
|
||||||
|
of this function.
|
||||||
|
|
||||||
|
### Rust Pattern
|
||||||
|
|
||||||
|
This ownership property translates well in Rust. We have decided to
|
||||||
|
use the `Box<T>` type to represent an owned pointer. `Box<T>` drops
|
||||||
|
its content when it's dropped.
|
||||||
|
|
||||||
|
Consequently, apart from other patterns, the code above can be written
|
||||||
|
as follows in Rust:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wasm_importtype_new(
|
||||||
|
module: Box<wasm_name_t>,
|
||||||
|
name: Box<wasm_name_t>,
|
||||||
|
extern_type: Box<wasm_externtype_t>,
|
||||||
|
) -> Box<wasm_importtype_t> {
|
||||||
|
…
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
By reading the code, it is clear that `wasm_importtype_new` takes the
|
||||||
|
ownership for `module`, `name`, and `extern_type`, and that the result
|
||||||
|
is owned by the caller.
|
||||||
|
|
||||||
|
## `const *T`
|
||||||
|
|
||||||
|
A constant pointer can be interpreted in C as an immutable
|
||||||
|
pointer. Without the [`own`] annotation, it means the ownership is not
|
||||||
|
transfered anywhere (see [the Ownerships Section][#ownerships]).
|
||||||
|
|
||||||
|
### Rust Pattern
|
||||||
|
|
||||||
|
`const *T` translates to Rust as `&T`, it's a reference.
|
||||||
|
|
||||||
|
## Null Pointer
|
||||||
|
|
||||||
|
The [`wasm.h`] header does not say anything about null pointer. The
|
||||||
|
behavior we agreed on in that passing a null pointer where it is not
|
||||||
|
expected (i.e. everywhere) will make the function to return null too
|
||||||
|
with no error.
|
||||||
|
|
||||||
|
### Rust Pattern
|
||||||
|
|
||||||
|
A nice type property in Rust is that it is possible to write
|
||||||
|
`Option<NonNull<T>>` to nicely handle null pointer of kind `T`. For an
|
||||||
|
argument, it translates as follows:
|
||||||
|
|
||||||
|
* When the given pointer is null, the argument holds `None`,
|
||||||
|
* When the given pointer is not null, the arguments holds
|
||||||
|
`Some(NonNull<T>)`.
|
||||||
|
|
||||||
|
Considering [the Ownerships Section][#ownerships], if the pointer is
|
||||||
|
owned, we can also write `Option<Box<T>>`. This pattern is largely
|
||||||
|
used in this codebase to represent a “nullable” owned
|
||||||
|
pointer. Consequently, a code like:
|
||||||
|
|
||||||
|
```c
|
||||||
|
WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new(
|
||||||
|
own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*);
|
||||||
|
```
|
||||||
|
|
||||||
|
translates into Rust as:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wasm_importtype_new(
|
||||||
|
module: Option<Box<wasm_name_t>>,
|
||||||
|
name: Option<Box<wasm_name_t>>,
|
||||||
|
extern_type: Option<Box<wasm_externtype_t>>,
|
||||||
|
) -> Option<Box<wasm_importtype_t>> {
|
||||||
|
Some(Box::new(wasm_importtype_t {
|
||||||
|
name: name?,
|
||||||
|
module: module?,
|
||||||
|
extern_type: extern_type?,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
What `name?` (and others) means? It is basically [the `Try` trait
|
||||||
|
implemented for
|
||||||
|
`Option`](https://doc.rust-lang.org/std/ops/trait.Try.html#impl-Try):
|
||||||
|
It returns `None` if the value is `None`, otherwise it unwraps the
|
||||||
|
`Option`.
|
||||||
|
|
||||||
|
Because the function returns `Option<Box<T>>`, `None` represents a
|
||||||
|
null pointer.
|
||||||
|
|
||||||
|
Considering [the `const *T` Section][#const-t], if the pointer is not
|
||||||
|
owned, we can either write `Option<NonNull<T>>` or `Option<&T>`. It
|
||||||
|
has been decided to use the second pattern in all the codebase.
|
||||||
|
|
||||||
|
## Destructors
|
||||||
|
|
||||||
|
The [`wasm.h`] defines `wasm_*_delete` functions. It represents destructors.
|
||||||
|
|
||||||
|
## Rust Pattern
|
||||||
|
|
||||||
|
The destructors in Rust translate as follow:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_*_delete(_: Option<Box<wasm_*_t>>) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Box<T>` will take the ownership of the value. It means that Rust will
|
||||||
|
drop it automatically as soon as it goes out of the
|
||||||
|
scope. Consequently, the “C destructors” really are the “Rust
|
||||||
|
destructors”.
|
||||||
|
|
||||||
|
The `Option` is here to handle the situation where a null pointer is
|
||||||
|
passed to the destructor.
|
||||||
|
|
||||||
|
|
||||||
|
[`own`](https://github.com/wasmerio/wasmer/blob/f548f268f2335693b97ad7ca08af72c320daf59a/lib/c-api/tests/wasm_c_api/wasm-c-api/include/wasm.h#L46-L65)
|
||||||
|
[`wasm.h`](https://github.com/wasmerio/wasmer/blob/f548f268f2335693b97ad7ca08af72c320daf59a/lib/c-api/tests/wasm_c_api/wasm-c-api/include/wasm.h)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::error::{update_last_error, CApiError};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer::Engine;
|
use wasmer::Engine;
|
||||||
@@ -8,7 +9,10 @@ use wasmer_engine_native::Native;
|
|||||||
#[cfg(feature = "object-file")]
|
#[cfg(feature = "object-file")]
|
||||||
use wasmer_engine_object_file::ObjectFile;
|
use wasmer_engine_object_file::ObjectFile;
|
||||||
|
|
||||||
/// this can be a wasmer-specific type with wasmer-specific functions for manipulating it
|
/// Kind of compilers that can be used by the engines.
|
||||||
|
///
|
||||||
|
/// This is a Wasmer-specific type with Wasmer-specific functions for
|
||||||
|
/// manipulating it.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum wasmer_compiler_t {
|
pub enum wasmer_compiler_t {
|
||||||
@@ -33,6 +37,10 @@ impl Default for wasmer_compiler_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kind of engines that can be used by the store.
|
||||||
|
///
|
||||||
|
/// This is a Wasmer-specific type with Wasmer-specific functions for
|
||||||
|
/// manipulating it.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@@ -58,8 +66,9 @@ impl Default for wasmer_engine_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A configuration holds the compiler and the engine used by the store.
|
||||||
|
///
|
||||||
/// cbindgen:ignore
|
/// cbindgen:ignore
|
||||||
/// this can be a wasmer-specific type with wasmer-specific functions for manipulating it
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct wasm_config_t {
|
pub struct wasm_config_t {
|
||||||
@@ -67,12 +76,15 @@ pub struct wasm_config_t {
|
|||||||
engine: wasmer_engine_t,
|
engine: wasmer_engine_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new Wasmer configuration.
|
||||||
|
///
|
||||||
/// cbindgen:ignore
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_config_new() -> Box<wasm_config_t> {
|
pub extern "C" fn wasm_config_new() -> Box<wasm_config_t> {
|
||||||
Box::new(wasm_config_t::default())
|
Box::new(wasm_config_t::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the compiler to use.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_config_set_compiler(
|
pub extern "C" fn wasm_config_set_compiler(
|
||||||
config: &mut wasm_config_t,
|
config: &mut wasm_config_t,
|
||||||
@@ -81,13 +93,17 @@ pub extern "C" fn wasm_config_set_compiler(
|
|||||||
config.compiler = compiler;
|
config.compiler = compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the engine to use.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_config_set_engine(config: &mut wasm_config_t, engine: wasmer_engine_t) {
|
pub extern "C" fn wasm_config_set_engine(config: &mut wasm_config_t, engine: wasmer_engine_t) {
|
||||||
config.engine = engine;
|
config.engine = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An engine is used by the store to drive the compilation and the
|
||||||
|
/// execution of a WebAssembly module.
|
||||||
|
///
|
||||||
/// cbindgen:ignore
|
/// cbindgen:ignore
|
||||||
#[allow(non_camel_case_types)]
|
#[repr(C)]
|
||||||
pub struct wasm_engine_t {
|
pub struct wasm_engine_t {
|
||||||
pub(crate) inner: Arc<dyn Engine + Send + Sync>,
|
pub(crate) inner: Arc<dyn Engine + Send + Sync>,
|
||||||
}
|
}
|
||||||
@@ -112,6 +128,7 @@ fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
|
|||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(all(feature = "jit", feature = "compiler"))] {
|
if #[cfg(all(feature = "jit", feature = "compiler"))] {
|
||||||
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||||
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
|
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
|
||||||
@@ -121,6 +138,7 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
else if #[cfg(feature = "jit")] {
|
else if #[cfg(feature = "jit")] {
|
||||||
// Headless JIT
|
// Headless JIT
|
||||||
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||||
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(JIT::headless().engine());
|
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(JIT::headless().engine());
|
||||||
@@ -128,6 +146,7 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if #[cfg(all(feature = "native", feature = "compiler"))] {
|
else if #[cfg(all(feature = "native", feature = "compiler"))] {
|
||||||
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||||
let mut compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
|
let mut compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
|
||||||
@@ -136,6 +155,7 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if #[cfg(feature = "native")] {
|
else if #[cfg(feature = "native")] {
|
||||||
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||||
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(Native::headless().engine());
|
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(Native::headless().engine());
|
||||||
@@ -145,6 +165,7 @@ cfg_if! {
|
|||||||
// There are currently no uses of the object-file engine + compiler from the C API.
|
// There are currently no uses of the object-file engine + compiler from the C API.
|
||||||
// So if we get here, we default to headless mode regardless of if `compiler` is enabled.
|
// So if we get here, we default to headless mode regardless of if `compiler` is enabled.
|
||||||
else if #[cfg(feature = "object-file")] {
|
else if #[cfg(feature = "object-file")] {
|
||||||
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||||
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(ObjectFile::headless().engine());
|
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(ObjectFile::headless().engine());
|
||||||
@@ -152,6 +173,7 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
||||||
unimplemented!("The JITEngine is not attached; You might want to recompile `wasmer_c_api` with `--feature jit`");
|
unimplemented!("The JITEngine is not attached; You might want to recompile `wasmer_c_api` with `--feature jit`");
|
||||||
@@ -161,14 +183,24 @@ cfg_if! {
|
|||||||
|
|
||||||
/// cbindgen:ignore
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_engine_delete(_wasm_engine_address: Option<Box<wasm_engine_t>>) {}
|
pub unsafe extern "C" fn wasm_engine_delete(_engine: Option<Box<wasm_engine_t>>) {}
|
||||||
|
|
||||||
/// cbindgen:ignore
|
/// cbindgen:ignore
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_engine_new_with_config(
|
pub extern "C" fn wasm_engine_new_with_config(
|
||||||
config: Box<wasm_config_t>,
|
config: Box<wasm_config_t>,
|
||||||
) -> Option<Box<wasm_engine_t>> {
|
) -> Option<Box<wasm_engine_t>> {
|
||||||
// TODO: return useful error messages in failure branches
|
fn return_with_error<M>(msg: M) -> Option<Box<wasm_engine_t>>
|
||||||
|
where
|
||||||
|
M: ToString,
|
||||||
|
{
|
||||||
|
update_last_error(CApiError {
|
||||||
|
msg: msg.to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "compiler")] {
|
if #[cfg(feature = "compiler")] {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
@@ -178,7 +210,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "cranelift")] {
|
if #[cfg(feature = "cranelift")] {
|
||||||
Box::new(wasmer_compiler_cranelift::Cranelift::default())
|
Box::new(wasmer_compiler_cranelift::Cranelift::default())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `cranelift` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -187,7 +219,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "llvm")] {
|
if #[cfg(feature = "llvm")] {
|
||||||
Box::new(wasmer_compiler_llvm::LLVM::default())
|
Box::new(wasmer_compiler_llvm::LLVM::default())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `llvm` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -196,7 +228,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "singlepass")] {
|
if #[cfg(feature = "singlepass")] {
|
||||||
Box::new(wasmer_compiler_singlepass::Singlepass::default())
|
Box::new(wasmer_compiler_singlepass::Singlepass::default())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `singlepass` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -208,7 +240,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "jit")] {
|
if #[cfg(feature = "jit")] {
|
||||||
Arc::new(JIT::new(&*compiler_config).engine())
|
Arc::new(JIT::new(&*compiler_config).engine())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `jit` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -217,7 +249,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "native")] {
|
if #[cfg(feature = "native")] {
|
||||||
Arc::new(Native::new(&mut *compiler_config).engine())
|
Arc::new(Native::new(&mut *compiler_config).engine())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `native` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -228,7 +260,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "object-file")] {
|
if #[cfg(feature = "object-file")] {
|
||||||
Arc::new(ObjectFile::headless().engine())
|
Arc::new(ObjectFile::headless().engine())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `object-file` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -241,7 +273,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "jit")] {
|
if #[cfg(feature = "jit")] {
|
||||||
Arc::new(JIT::headless().engine())
|
Arc::new(JIT::headless().engine())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `jit` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -250,7 +282,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "native")] {
|
if #[cfg(feature = "native")] {
|
||||||
Arc::new(Native::headless().engine())
|
Arc::new(Native::headless().engine())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `native` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -259,7 +291,7 @@ pub extern "C" fn wasm_engine_new_with_config(
|
|||||||
if #[cfg(feature = "object-file")] {
|
if #[cfg(feature = "object-file")] {
|
||||||
Arc::new(ObjectFile::headless().engine())
|
Arc::new(ObjectFile::headless().engine())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return return_with_error("Wasmer has not been compiled with the `object-file` feature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
64
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
64
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
@@ -7,6 +7,7 @@ use std::ffi::c_void;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer::{Function, Instance, RuntimeError, Val};
|
use wasmer::{Function, Instance, RuntimeError, Val};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub struct wasm_func_t {
|
pub struct wasm_func_t {
|
||||||
pub(crate) inner: Function,
|
pub(crate) inner: Function,
|
||||||
@@ -32,12 +33,15 @@ pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_func_new(
|
pub unsafe extern "C" fn wasm_func_new(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
ft: &wasm_functype_t,
|
function_type: Option<&wasm_functype_t>,
|
||||||
callback: wasm_func_callback_t,
|
callback: Option<wasm_func_callback_t>,
|
||||||
) -> Option<Box<wasm_func_t>> {
|
) -> Option<Box<wasm_func_t>> {
|
||||||
// TODO: handle null pointers?
|
let store = store?;
|
||||||
let func_sig = ft.sig();
|
let function_type = function_type?;
|
||||||
|
let callback = callback?;
|
||||||
|
|
||||||
|
let func_sig = &function_type.inner().function_type;
|
||||||
let num_rets = func_sig.results().len();
|
let num_rets = func_sig.results().len();
|
||||||
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
||||||
let processed_args: wasm_val_vec_t = args
|
let processed_args: wasm_val_vec_t = args
|
||||||
@@ -84,14 +88,17 @@ pub unsafe extern "C" fn wasm_func_new(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_func_new_with_env(
|
pub unsafe extern "C" fn wasm_func_new_with_env(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
ft: &wasm_functype_t,
|
function_type: Option<&wasm_functype_t>,
|
||||||
callback: wasm_func_callback_with_env_t,
|
callback: Option<wasm_func_callback_with_env_t>,
|
||||||
env: *mut c_void,
|
env: *mut c_void,
|
||||||
finalizer: wasm_env_finalizer_t,
|
finalizer: wasm_env_finalizer_t,
|
||||||
) -> Option<Box<wasm_func_t>> {
|
) -> Option<Box<wasm_func_t>> {
|
||||||
// TODO: handle null pointers?
|
let store = store?;
|
||||||
let func_sig = ft.sig();
|
let function_type = function_type?;
|
||||||
|
let callback = callback?;
|
||||||
|
|
||||||
|
let func_sig = &function_type.inner().function_type;
|
||||||
let num_rets = func_sig.results().len();
|
let num_rets = func_sig.results().len();
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -154,10 +161,13 @@ pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_func_call(
|
pub unsafe extern "C" fn wasm_func_call(
|
||||||
func: &wasm_func_t,
|
func: Option<&wasm_func_t>,
|
||||||
args: &wasm_val_vec_t,
|
args: Option<&wasm_val_vec_t>,
|
||||||
results: &mut wasm_val_vec_t,
|
results: &mut wasm_val_vec_t,
|
||||||
) -> Option<Box<wasm_trap_t>> {
|
) -> Option<Box<wasm_trap_t>> {
|
||||||
|
let func = func?;
|
||||||
|
let args = args?;
|
||||||
|
|
||||||
let params = args
|
let params = args
|
||||||
.into_slice()
|
.into_slice()
|
||||||
.map(|slice| {
|
.map(|slice| {
|
||||||
@@ -165,18 +175,34 @@ pub unsafe extern "C" fn wasm_func_call(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(TryInto::try_into)
|
.map(TryInto::try_into)
|
||||||
.collect::<Result<Vec<Val>, _>>()
|
.collect::<Result<Vec<Val>, _>>()
|
||||||
.expect("Argument conversion failed")
|
.expect("Arguments conversion failed")
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
match func.inner.call(¶ms) {
|
match func.inner.call(¶ms) {
|
||||||
Ok(wasm_results) => {
|
Ok(wasm_results) => {
|
||||||
*results = wasm_results
|
let vals = wasm_results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(TryInto::try_into)
|
.map(TryInto::try_into)
|
||||||
.collect::<Result<Vec<wasm_val_t>, _>>()
|
.collect::<Result<Vec<wasm_val_t>, _>>()
|
||||||
.expect("Argument conversion failed")
|
.expect("Results conversion failed");
|
||||||
.into();
|
|
||||||
|
// `results` is an uninitialized vector. Set a new value.
|
||||||
|
if results.is_uninitialized() {
|
||||||
|
*results = vals.into();
|
||||||
|
}
|
||||||
|
// `results` is an initialized but empty vector. Fill it
|
||||||
|
// item per item.
|
||||||
|
else {
|
||||||
|
let slice = results
|
||||||
|
.into_slice_mut()
|
||||||
|
.expect("`wasm_func_call`, results' size is greater than 0 but data is NULL");
|
||||||
|
|
||||||
|
for (result, value) in slice.iter_mut().zip(vals.iter()) {
|
||||||
|
(*result).kind = value.kind;
|
||||||
|
(*result).of = value.of;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -195,6 +221,8 @@ pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_func_type(func: &wasm_func_t) -> Box<wasm_functype_t> {
|
pub extern "C" fn wasm_func_type(func: Option<&wasm_func_t>) -> Option<Box<wasm_functype_t>> {
|
||||||
Box::new(wasm_functype_t::new(func.inner.ty().clone()))
|
let func = func?;
|
||||||
|
|
||||||
|
Some(Box::new(wasm_functype_t::new(func.inner.ty().clone())))
|
||||||
}
|
}
|
||||||
|
|||||||
40
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
40
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
@@ -1,6 +1,7 @@
|
|||||||
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 crate::error::update_last_error;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use wasmer::{Global, Val};
|
use wasmer::{Global, Val};
|
||||||
|
|
||||||
@@ -12,14 +13,18 @@ pub struct wasm_global_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_global_new(
|
pub unsafe extern "C" fn wasm_global_new(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
gt: &wasm_globaltype_t,
|
global_type: Option<&wasm_globaltype_t>,
|
||||||
val: &wasm_val_t,
|
val: Option<&wasm_val_t>,
|
||||||
) -> Option<Box<wasm_global_t>> {
|
) -> Option<Box<wasm_global_t>> {
|
||||||
let gt = gt.as_globaltype();
|
let store = store?;
|
||||||
|
let global_type = global_type?;
|
||||||
|
let val = val?;
|
||||||
|
|
||||||
|
let global_type = &global_type.inner().global_type;
|
||||||
let wasm_val = val.try_into().ok()?;
|
let wasm_val = val.try_into().ok()?;
|
||||||
let store = &store.inner;
|
let store = &store.inner;
|
||||||
let global = if gt.mutability.is_mutable() {
|
let global = if global_type.mutability.is_mutable() {
|
||||||
Global::new_mut(store, wasm_val)
|
Global::new_mut(store, wasm_val)
|
||||||
} else {
|
} else {
|
||||||
Global::new(store, wasm_val)
|
Global::new(store, wasm_val)
|
||||||
@@ -33,23 +38,32 @@ pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>)
|
|||||||
|
|
||||||
// TODO: figure out if these should be deep or shallow copies
|
// TODO: figure out if these should be deep or shallow copies
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_global_copy(wasm_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 {
|
||||||
inner: wasm_global.inner.clone(),
|
inner: global.inner.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_global_get(wasm_global: &wasm_global_t, out: &mut wasm_val_t) {
|
pub unsafe extern "C" fn wasm_global_get(
|
||||||
let value = wasm_global.inner.get();
|
global: &wasm_global_t,
|
||||||
|
// own
|
||||||
|
out: &mut wasm_val_t,
|
||||||
|
) {
|
||||||
|
let value = global.inner.get();
|
||||||
*out = value.try_into().unwrap();
|
*out = value.try_into().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Note: This function returns nothing by design but it can raise an
|
||||||
|
/// error if setting a new value fails.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_global_set(wasm_global: &mut wasm_global_t, val: &wasm_val_t) {
|
pub unsafe extern "C" fn wasm_global_set(global: &mut wasm_global_t, val: &wasm_val_t) {
|
||||||
let value: Val = val.try_into().unwrap();
|
let value: Val = val.try_into().unwrap();
|
||||||
wasm_global.inner.set(value);
|
|
||||||
|
if let Err(e) = global.inner.set(value) {
|
||||||
|
update_last_error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -61,6 +75,6 @@ pub unsafe extern "C" fn wasm_global_same(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_global_type(wasm_global: &wasm_global_t) -> Box<wasm_globaltype_t> {
|
pub extern "C" fn wasm_global_type(global: &wasm_global_t) -> Box<wasm_globaltype_t> {
|
||||||
Box::new(wasm_globaltype_t::new(wasm_global.inner.ty().clone()))
|
Box::new(wasm_globaltype_t::new(global.inner.ty().clone()))
|
||||||
}
|
}
|
||||||
|
|||||||
19
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
19
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
@@ -11,11 +11,14 @@ pub struct wasm_memory_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_memory_new(
|
pub unsafe extern "C" fn wasm_memory_new(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
mt: &wasm_memorytype_t,
|
memory_type: Option<&wasm_memorytype_t>,
|
||||||
) -> Option<Box<wasm_memory_t>> {
|
) -> Option<Box<wasm_memory_t>> {
|
||||||
let md = mt.as_memorytype().clone();
|
let store = store?;
|
||||||
let memory = c_try!(Memory::new(&store.inner, md));
|
let memory_type = memory_type?;
|
||||||
|
|
||||||
|
let memory_type = memory_type.inner().memory_type.clone();
|
||||||
|
let memory = c_try!(Memory::new(&store.inner, memory_type));
|
||||||
|
|
||||||
Some(Box::new(wasm_memory_t { inner: memory }))
|
Some(Box::new(wasm_memory_t { inner: memory }))
|
||||||
}
|
}
|
||||||
@@ -33,8 +36,12 @@ pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_me
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_memory_type(memory: &wasm_memory_t) -> Box<wasm_memorytype_t> {
|
pub unsafe extern "C" fn wasm_memory_type(
|
||||||
Box::new(wasm_memorytype_t::new(memory.inner.ty().clone()))
|
memory: Option<&wasm_memory_t>,
|
||||||
|
) -> Option<Box<wasm_memorytype_t>> {
|
||||||
|
let memory = memory?;
|
||||||
|
|
||||||
|
Some(Box::new(wasm_memorytype_t::new(memory.inner.ty().clone())))
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a raw pointer into bytes
|
// get a raw pointer into bytes
|
||||||
|
|||||||
51
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
51
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
@@ -6,7 +6,6 @@ mod table;
|
|||||||
pub use function::*;
|
pub use function::*;
|
||||||
pub use global::*;
|
pub use global::*;
|
||||||
pub use memory::*;
|
pub use memory::*;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
pub use table::*;
|
pub use table::*;
|
||||||
use wasmer::{Extern, Instance};
|
use wasmer::{Extern, Instance};
|
||||||
@@ -22,10 +21,9 @@ wasm_declare_boxed_vec!(extern);
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_func_as_extern(
|
pub unsafe extern "C" fn wasm_func_as_extern(
|
||||||
func_ptr: Option<NonNull<wasm_func_t>>,
|
func: Option<&wasm_func_t>,
|
||||||
) -> Option<Box<wasm_extern_t>> {
|
) -> Option<Box<wasm_extern_t>> {
|
||||||
let func_ptr = func_ptr?;
|
let func = func?;
|
||||||
let func = func_ptr.as_ref();
|
|
||||||
|
|
||||||
Some(Box::new(wasm_extern_t {
|
Some(Box::new(wasm_extern_t {
|
||||||
instance: func.instance.clone(),
|
instance: func.instance.clone(),
|
||||||
@@ -35,13 +33,12 @@ pub unsafe extern "C" fn wasm_func_as_extern(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_global_as_extern(
|
pub unsafe extern "C" fn wasm_global_as_extern(
|
||||||
global_ptr: Option<NonNull<wasm_global_t>>,
|
global: Option<&wasm_global_t>,
|
||||||
) -> Option<Box<wasm_extern_t>> {
|
) -> Option<Box<wasm_extern_t>> {
|
||||||
let global_ptr = global_ptr?;
|
let global = global?;
|
||||||
let global = global_ptr.as_ref();
|
|
||||||
|
|
||||||
Some(Box::new(wasm_extern_t {
|
Some(Box::new(wasm_extern_t {
|
||||||
// update this if global does hold onto an `instance`
|
// TODO: update this if global does hold onto an `instance`
|
||||||
instance: None,
|
instance: None,
|
||||||
inner: Extern::Global(global.inner.clone()),
|
inner: Extern::Global(global.inner.clone()),
|
||||||
}))
|
}))
|
||||||
@@ -49,13 +46,12 @@ pub unsafe extern "C" fn wasm_global_as_extern(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_memory_as_extern(
|
pub unsafe extern "C" fn wasm_memory_as_extern(
|
||||||
memory_ptr: Option<NonNull<wasm_memory_t>>,
|
memory: Option<&wasm_memory_t>,
|
||||||
) -> Option<Box<wasm_extern_t>> {
|
) -> Option<Box<wasm_extern_t>> {
|
||||||
let memory_ptr = memory_ptr?;
|
let memory = memory?;
|
||||||
let memory = memory_ptr.as_ref();
|
|
||||||
|
|
||||||
Some(Box::new(wasm_extern_t {
|
Some(Box::new(wasm_extern_t {
|
||||||
// update this if global does hold onto an `instance`
|
// TODO: update this if global does hold onto an `instance`
|
||||||
instance: None,
|
instance: None,
|
||||||
inner: Extern::Memory(memory.inner.clone()),
|
inner: Extern::Memory(memory.inner.clone()),
|
||||||
}))
|
}))
|
||||||
@@ -63,13 +59,12 @@ pub unsafe extern "C" fn wasm_memory_as_extern(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_table_as_extern(
|
pub unsafe extern "C" fn wasm_table_as_extern(
|
||||||
table_ptr: Option<NonNull<wasm_table_t>>,
|
table: Option<&wasm_table_t>,
|
||||||
) -> Option<Box<wasm_extern_t>> {
|
) -> Option<Box<wasm_extern_t>> {
|
||||||
let table_ptr = table_ptr?;
|
let table = table?;
|
||||||
let table = table_ptr.as_ref();
|
|
||||||
|
|
||||||
Some(Box::new(wasm_extern_t {
|
Some(Box::new(wasm_extern_t {
|
||||||
// update this if global does hold onto an `instance`
|
// TODO: update this if global does hold onto an `instance`
|
||||||
instance: None,
|
instance: None,
|
||||||
inner: Extern::Table(table.inner.clone()),
|
inner: Extern::Table(table.inner.clone()),
|
||||||
}))
|
}))
|
||||||
@@ -77,10 +72,10 @@ pub unsafe extern "C" fn wasm_table_as_extern(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_extern_as_func(
|
pub unsafe extern "C" fn wasm_extern_as_func(
|
||||||
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
r#extern: Option<&wasm_extern_t>,
|
||||||
) -> Option<Box<wasm_func_t>> {
|
) -> Option<Box<wasm_func_t>> {
|
||||||
let extern_ptr = extern_ptr?;
|
let r#extern = r#extern?;
|
||||||
let r#extern = extern_ptr.as_ref();
|
|
||||||
if let Extern::Function(f) = &r#extern.inner {
|
if let Extern::Function(f) = &r#extern.inner {
|
||||||
Some(Box::new(wasm_func_t {
|
Some(Box::new(wasm_func_t {
|
||||||
inner: f.clone(),
|
inner: f.clone(),
|
||||||
@@ -93,10 +88,10 @@ pub unsafe extern "C" fn wasm_extern_as_func(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_extern_as_global(
|
pub unsafe extern "C" fn wasm_extern_as_global(
|
||||||
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
r#extern: Option<&wasm_extern_t>,
|
||||||
) -> Option<Box<wasm_global_t>> {
|
) -> Option<Box<wasm_global_t>> {
|
||||||
let extern_ptr = extern_ptr?;
|
let r#extern = r#extern?;
|
||||||
let r#extern = extern_ptr.as_ref();
|
|
||||||
if let Extern::Global(g) = &r#extern.inner {
|
if let Extern::Global(g) = &r#extern.inner {
|
||||||
Some(Box::new(wasm_global_t { inner: g.clone() }))
|
Some(Box::new(wasm_global_t { inner: g.clone() }))
|
||||||
} else {
|
} else {
|
||||||
@@ -106,10 +101,10 @@ pub unsafe extern "C" fn wasm_extern_as_global(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_extern_as_memory(
|
pub unsafe extern "C" fn wasm_extern_as_memory(
|
||||||
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
r#extern: Option<&wasm_extern_t>,
|
||||||
) -> Option<Box<wasm_memory_t>> {
|
) -> Option<Box<wasm_memory_t>> {
|
||||||
let extern_ptr = extern_ptr?;
|
let r#extern = r#extern?;
|
||||||
let r#extern = extern_ptr.as_ref();
|
|
||||||
if let Extern::Memory(m) = &r#extern.inner {
|
if let Extern::Memory(m) = &r#extern.inner {
|
||||||
Some(Box::new(wasm_memory_t { inner: m.clone() }))
|
Some(Box::new(wasm_memory_t { inner: m.clone() }))
|
||||||
} else {
|
} else {
|
||||||
@@ -119,10 +114,10 @@ pub unsafe extern "C" fn wasm_extern_as_memory(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_extern_as_table(
|
pub unsafe extern "C" fn wasm_extern_as_table(
|
||||||
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
r#extern: Option<&wasm_extern_t>,
|
||||||
) -> Option<Box<wasm_table_t>> {
|
) -> Option<Box<wasm_table_t>> {
|
||||||
let extern_ptr = extern_ptr?;
|
let r#extern = r#extern?;
|
||||||
let r#extern = extern_ptr.as_ref();
|
|
||||||
if let Extern::Table(t) = &r#extern.inner {
|
if let Extern::Table(t) = &r#extern.inner {
|
||||||
Some(Box::new(wasm_table_t { inner: t.clone() }))
|
Some(Box::new(wasm_table_t { inner: t.clone() }))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
30
lib/c-api/src/wasm_c_api/externals/table.rs
vendored
30
lib/c-api/src/wasm_c_api/externals/table.rs
vendored
@@ -10,44 +10,46 @@ pub struct wasm_table_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_table_new(
|
pub unsafe extern "C" fn wasm_table_new(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
tt: &wasm_tabletype_t,
|
table_type: Option<&wasm_tabletype_t>,
|
||||||
init: *const wasm_ref_t,
|
init: *const wasm_ref_t,
|
||||||
) -> Option<Box<wasm_table_t>> {
|
) -> Option<Box<wasm_table_t>> {
|
||||||
let tt = tt.as_tabletype().clone();
|
let store = store?;
|
||||||
|
let table_type = table_type?;
|
||||||
|
|
||||||
|
let table_type = table_type.inner().table_type.clone();
|
||||||
let init_val = todo!("get val from init somehow");
|
let init_val = todo!("get val from init somehow");
|
||||||
let table = c_try!(Table::new(&store.inner, tt, init_val));
|
/*
|
||||||
|
let table = c_try!(Table::new(&store.inner, table_type, init_val));
|
||||||
|
|
||||||
Some(Box::new(wasm_table_t { inner: table }))
|
Some(Box::new(wasm_table_t { inner: table }))
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_table_delete(_table: Option<Box<wasm_table_t>>) {}
|
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(wasm_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 {
|
||||||
inner: wasm_table.inner.clone(),
|
inner: table.inner.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_table_same(
|
pub unsafe extern "C" fn wasm_table_same(table1: &wasm_table_t, table2: &wasm_table_t) -> bool {
|
||||||
wasm_table1: &wasm_table_t,
|
table1.inner.same(&table2.inner)
|
||||||
wasm_table2: &wasm_table_t,
|
|
||||||
) -> bool {
|
|
||||||
wasm_table1.inner.same(&wasm_table2.inner)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_table_size(wasm_table: &wasm_table_t) -> usize {
|
pub unsafe extern "C" fn wasm_table_size(table: &wasm_table_t) -> usize {
|
||||||
wasm_table.inner.size() as _
|
table.inner.size() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_table_grow(
|
pub unsafe extern "C" fn wasm_table_grow(
|
||||||
_wasm_table: &mut wasm_table_t,
|
_table: &mut wasm_table_t,
|
||||||
_delta: wasm_table_size_t,
|
_delta: wasm_table_size_t,
|
||||||
_init: *mut wasm_ref_t,
|
_init: *mut wasm_ref_t,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use super::trap::wasm_trap_t;
|
|||||||
use crate::ordered_resolver::OrderedResolver;
|
use crate::ordered_resolver::OrderedResolver;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer::{Extern, Instance};
|
use wasmer::{Extern, Instance, InstantiationError};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub struct wasm_instance_t {
|
pub struct wasm_instance_t {
|
||||||
@@ -14,12 +14,14 @@ pub struct wasm_instance_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_instance_new(
|
pub unsafe extern "C" fn wasm_instance_new(
|
||||||
_store: &wasm_store_t,
|
_store: Option<&wasm_store_t>,
|
||||||
module: &wasm_module_t,
|
module: Option<&wasm_module_t>,
|
||||||
imports: &wasm_extern_vec_t,
|
imports: Option<&wasm_extern_vec_t>,
|
||||||
// own
|
traps: *mut *mut wasm_trap_t,
|
||||||
_traps: *mut *mut wasm_trap_t,
|
|
||||||
) -> Option<Box<wasm_instance_t>> {
|
) -> Option<Box<wasm_instance_t>> {
|
||||||
|
let module = module?;
|
||||||
|
let imports = imports?;
|
||||||
|
|
||||||
let wasm_module = &module.inner;
|
let wasm_module = &module.inner;
|
||||||
let module_imports = wasm_module.imports();
|
let module_imports = wasm_module.imports();
|
||||||
let module_import_count = module_imports.len();
|
let module_import_count = module_imports.len();
|
||||||
@@ -32,7 +34,23 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let instance = Arc::new(c_try!(Instance::new(wasm_module, &resolver)));
|
let instance = match Instance::new(wasm_module, &resolver) {
|
||||||
|
Ok(instance) => Arc::new(instance),
|
||||||
|
|
||||||
|
Err(InstantiationError::Link(link_error)) => {
|
||||||
|
crate::error::update_last_error(link_error);
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(InstantiationError::Start(runtime_error)) => {
|
||||||
|
let trap: Box<wasm_trap_t> = Box::new(runtime_error.into());
|
||||||
|
*traps = Box::into_raw(trap);
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Some(Box::new(wasm_instance_t { inner: instance }))
|
Some(Box::new(wasm_instance_t { inner: instance }))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +60,7 @@ pub unsafe extern "C" fn wasm_instance_delete(_instance: Option<Box<wasm_instanc
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_instance_exports(
|
pub unsafe extern "C" fn wasm_instance_exports(
|
||||||
instance: &wasm_instance_t,
|
instance: &wasm_instance_t,
|
||||||
// TODO: review types on wasm_declare_vec, handle the optional pointer part properly
|
// own
|
||||||
out: &mut wasm_extern_vec_t,
|
out: &mut wasm_extern_vec_t,
|
||||||
) {
|
) {
|
||||||
let instance = &instance.inner;
|
let instance = &instance.inner;
|
||||||
@@ -55,6 +73,7 @@ pub unsafe extern "C" fn wasm_instance_exports(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::into_raw(Box::new(wasm_extern_t {
|
Box::into_raw(Box::new(wasm_extern_t {
|
||||||
instance: Some(Arc::clone(instance)),
|
instance: Some(Arc::clone(instance)),
|
||||||
inner: r#extern.clone(),
|
inner: r#extern.clone(),
|
||||||
@@ -65,6 +84,6 @@ pub unsafe extern "C" fn wasm_instance_exports(
|
|||||||
|
|
||||||
out.size = extern_vec.len();
|
out.size = extern_vec.len();
|
||||||
out.data = extern_vec.as_mut_ptr();
|
out.data = extern_vec.as_mut_ptr();
|
||||||
// TODO: double check that the destructor will work correctly here
|
|
||||||
mem::forget(extern_vec);
|
mem::forget(extern_vec);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ macro_rules! wasm_declare_vec_inner {
|
|||||||
macro_rules! wasm_declare_vec {
|
macro_rules! wasm_declare_vec {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct [<wasm_ $name _vec_t>] {
|
pub struct [<wasm_ $name _vec_t>] {
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
@@ -56,12 +57,24 @@ macro_rules! wasm_declare_vec {
|
|||||||
|
|
||||||
impl [<wasm_ $name _vec_t>] {
|
impl [<wasm_ $name _vec_t>] {
|
||||||
pub unsafe fn into_slice(&self) -> Option<&[[<wasm_ $name _t>]]>{
|
pub unsafe fn into_slice(&self) -> Option<&[[<wasm_ $name _t>]]>{
|
||||||
if self.data.is_null() {
|
if self.is_uninitialized() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(::std::slice::from_raw_parts(self.data, self.size))
|
Some(::std::slice::from_raw_parts(self.data, self.size))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn into_slice_mut(&mut self) -> Option<&mut [[<wasm_ $name _t>]]>{
|
||||||
|
if self.is_uninitialized() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(::std::slice::from_raw_parts_mut(self.data, self.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_uninitialized(&self) -> bool {
|
||||||
|
self.data.is_null()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: investigate possible memory leak on `init` (owned pointer)
|
// TODO: investigate possible memory leak on `init` (owned pointer)
|
||||||
@@ -108,6 +121,7 @@ macro_rules! wasm_declare_vec {
|
|||||||
macro_rules! wasm_declare_boxed_vec {
|
macro_rules! wasm_declare_boxed_vec {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct [<wasm_ $name _vec_t>] {
|
pub struct [<wasm_ $name _vec_t>] {
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
@@ -170,7 +184,7 @@ macro_rules! wasm_declare_boxed_vec {
|
|||||||
let vec = &mut *ptr;
|
let vec = &mut *ptr;
|
||||||
if !vec.data.is_null() {
|
if !vec.data.is_null() {
|
||||||
let data: Vec<*mut [<wasm_ $name _t>]> = Vec::from_raw_parts(vec.data, vec.size, vec.size);
|
let data: Vec<*mut [<wasm_ $name _t>]> = Vec::from_raw_parts(vec.data, vec.size, vec.size);
|
||||||
let data: Vec<Box<[<wasm_ $name _t>]>> = ::std::mem::transmute(data);
|
let _data: Vec<Box<[<wasm_ $name _t>]>> = ::std::mem::transmute(data);
|
||||||
vec.data = ::std::ptr::null_mut();
|
vec.data = ::std::ptr::null_mut();
|
||||||
vec.size = 0;
|
vec.size = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ use super::types::{
|
|||||||
wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t,
|
wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t,
|
||||||
wasm_importtype_vec_t,
|
wasm_importtype_vec_t,
|
||||||
};
|
};
|
||||||
use crate::error::update_last_error;
|
use crate::error::{update_last_error, CApiError};
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::slice;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer::Module;
|
use wasmer::Module;
|
||||||
|
|
||||||
@@ -14,14 +13,58 @@ pub struct wasm_module_t {
|
|||||||
pub(crate) inner: Arc<Module>,
|
pub(crate) inner: Arc<Module>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A WebAssembly module contains stateless WebAssembly code that has
|
||||||
|
/// already been compiled and can be instantiated multiple times.
|
||||||
|
///
|
||||||
|
/// Creates a new WebAssembly Module given the configuration
|
||||||
|
/// in the store.
|
||||||
|
///
|
||||||
|
/// ## Security
|
||||||
|
///
|
||||||
|
/// Before the code is compiled, it will be validated using the store
|
||||||
|
/// features.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use inline_c::assert_c;
|
||||||
|
/// # fn main() {
|
||||||
|
/// # (assert_c! {
|
||||||
|
/// # #include "tests/wasmer_wasm.h"
|
||||||
|
/// #
|
||||||
|
/// int main() {
|
||||||
|
/// wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
/// wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
///
|
||||||
|
/// wasm_byte_vec_t wat;
|
||||||
|
/// wasmer_byte_vec_new_from_string(&wat, "(module)");
|
||||||
|
/// wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
///
|
||||||
|
/// wasm_module_t* module = wasm_module_new(store, wasm);
|
||||||
|
/// assert(module);
|
||||||
|
///
|
||||||
|
/// wasm_byte_vec_delete(wasm);
|
||||||
|
/// wasm_byte_vec_delete(&wat);
|
||||||
|
/// wasm_module_delete(module);
|
||||||
|
/// wasm_store_delete(store);
|
||||||
|
/// wasm_engine_delete(engine);
|
||||||
|
///
|
||||||
|
/// return 0;
|
||||||
|
/// }
|
||||||
|
/// # })
|
||||||
|
/// # .success();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_module_new(
|
pub unsafe extern "C" fn wasm_module_new(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
bytes: &wasm_byte_vec_t,
|
bytes: Option<&wasm_byte_vec_t>,
|
||||||
) -> Option<Box<wasm_module_t>> {
|
) -> Option<Box<wasm_module_t>> {
|
||||||
// TODO: review lifetime of byte slice
|
let store = store?;
|
||||||
let wasm_byte_slice: &[u8] = slice::from_raw_parts_mut(bytes.data, bytes.size);
|
let bytes = bytes?;
|
||||||
let module = c_try!(Module::from_binary(&store.inner, wasm_byte_slice));
|
|
||||||
|
let bytes = bytes.into_slice()?;
|
||||||
|
let module = c_try!(Module::from_binary(&store.inner, bytes));
|
||||||
|
|
||||||
Some(Box::new(wasm_module_t {
|
Some(Box::new(wasm_module_t {
|
||||||
inner: Arc::new(module),
|
inner: Arc::new(module),
|
||||||
@@ -33,13 +76,24 @@ pub unsafe extern "C" fn wasm_module_delete(_module: Option<Box<wasm_module_t>>)
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_module_validate(
|
pub unsafe extern "C" fn wasm_module_validate(
|
||||||
store: &wasm_store_t,
|
store: Option<&wasm_store_t>,
|
||||||
bytes: &wasm_byte_vec_t,
|
bytes: Option<&wasm_byte_vec_t>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// TODO: review lifetime of byte slice.
|
let store = match store {
|
||||||
let wasm_byte_slice: &[u8] = slice::from_raw_parts(bytes.data, bytes.size);
|
Some(store) => store,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
let bytes = match bytes {
|
||||||
|
Some(bytes) => bytes,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(error) = Module::validate(&store.inner, wasm_byte_slice) {
|
let bytes = match bytes.into_slice() {
|
||||||
|
Some(bytes) => bytes,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(error) = Module::validate(&store.inner, bytes) {
|
||||||
update_last_error(error);
|
update_last_error(error);
|
||||||
|
|
||||||
false
|
false
|
||||||
@@ -51,6 +105,7 @@ pub unsafe extern "C" fn wasm_module_validate(
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_module_exports(
|
pub unsafe extern "C" fn wasm_module_exports(
|
||||||
module: &wasm_module_t,
|
module: &wasm_module_t,
|
||||||
|
// own
|
||||||
out: &mut wasm_exporttype_vec_t,
|
out: &mut wasm_exporttype_vec_t,
|
||||||
) {
|
) {
|
||||||
let exports = module
|
let exports = module
|
||||||
@@ -66,6 +121,7 @@ pub unsafe extern "C" fn wasm_module_exports(
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_module_imports(
|
pub unsafe extern "C" fn wasm_module_imports(
|
||||||
module: &wasm_module_t,
|
module: &wasm_module_t,
|
||||||
|
// own
|
||||||
out: &mut wasm_importtype_vec_t,
|
out: &mut wasm_importtype_vec_t,
|
||||||
) {
|
) {
|
||||||
let imports = module
|
let imports = module
|
||||||
@@ -86,7 +142,10 @@ pub unsafe extern "C" fn wasm_module_deserialize(
|
|||||||
// TODO: read config from store and use that to decide which compiler to use
|
// TODO: read config from store and use that to decide which compiler to use
|
||||||
|
|
||||||
let byte_slice = if bytes.is_null() || (&*bytes).into_slice().is_none() {
|
let byte_slice = if bytes.is_null() || (&*bytes).into_slice().is_none() {
|
||||||
// TODO: error handling here
|
update_last_error(CApiError {
|
||||||
|
msg: "`bytes` is null or represents an empty slice".to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
return None;
|
return None;
|
||||||
} else {
|
} else {
|
||||||
(&*bytes).into_slice().unwrap()
|
(&*bytes).into_slice().unwrap()
|
||||||
@@ -115,3 +174,364 @@ pub unsafe extern "C" fn wasm_module_serialize(
|
|||||||
};
|
};
|
||||||
*out_ptr = byte_vec.into();
|
*out_ptr = byte_vec.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use inline_c::assert_c;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_validate() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(&wat, "(module)");
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
assert(wasm_module_validate(store, wasm));
|
||||||
|
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_new() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(&wat, "(module)");
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
wasm_module_t* module = wasm_module_new(store, wasm);
|
||||||
|
assert(module);
|
||||||
|
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_exports() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(
|
||||||
|
&wat,
|
||||||
|
"(module\n"
|
||||||
|
" (func (export \"function\") (param i32 i64))\n"
|
||||||
|
" (global (export \"global\") i32 (i32.const 7))\n"
|
||||||
|
" (table (export \"table\") 0 funcref)\n"
|
||||||
|
" (memory (export \"memory\") 1))"
|
||||||
|
);
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
wasm_module_t* module = wasm_module_new(store, wasm);
|
||||||
|
assert(module);
|
||||||
|
|
||||||
|
wasm_exporttype_vec_t export_types;
|
||||||
|
wasm_module_exports(module, &export_types);
|
||||||
|
|
||||||
|
assert(export_types.size == 4);
|
||||||
|
|
||||||
|
{
|
||||||
|
wasm_exporttype_t* export_type = export_types.data[0];
|
||||||
|
|
||||||
|
const wasm_name_t* export_name = wasm_exporttype_name(export_type);
|
||||||
|
wasmer_assert_name(export_name, "function");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_exporttype_type(export_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_FUNC);
|
||||||
|
|
||||||
|
const wasm_functype_t* func_type = wasm_externtype_as_functype_const(extern_type);
|
||||||
|
|
||||||
|
const wasm_valtype_vec_t* func_params = wasm_functype_params(func_type);
|
||||||
|
assert(func_params && func_params->size == 2);
|
||||||
|
assert(wasm_valtype_kind(func_params->data[0]) == WASM_I32);
|
||||||
|
assert(wasm_valtype_kind(func_params->data[1]) == WASM_I64);
|
||||||
|
|
||||||
|
const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type);
|
||||||
|
assert(func_results && func_results->size == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
wasm_exporttype_t* export_type = export_types.data[1];
|
||||||
|
|
||||||
|
const wasm_name_t* export_name = wasm_exporttype_name(export_type);
|
||||||
|
wasmer_assert_name(export_name, "global");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_exporttype_type(export_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_GLOBAL);
|
||||||
|
|
||||||
|
const wasm_globaltype_t* global_type = wasm_externtype_as_globaltype_const(extern_type);
|
||||||
|
assert(wasm_valtype_kind(wasm_globaltype_content(global_type)) == WASM_I32);
|
||||||
|
assert(wasm_globaltype_mutability(global_type) == WASM_CONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
wasm_exporttype_t* export_type = export_types.data[2];
|
||||||
|
|
||||||
|
const wasm_name_t* export_name = wasm_exporttype_name(export_type);
|
||||||
|
wasmer_assert_name(export_name, "table");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_exporttype_type(export_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_TABLE);
|
||||||
|
|
||||||
|
const wasm_tabletype_t* table_type = wasm_externtype_as_tabletype_const(extern_type);
|
||||||
|
assert(wasm_valtype_kind(wasm_tabletype_element(table_type)) == WASM_FUNCREF);
|
||||||
|
|
||||||
|
const wasm_limits_t* table_limits = wasm_tabletype_limits(table_type);
|
||||||
|
assert(table_limits->min == 0);
|
||||||
|
assert(table_limits->max == wasm_limits_max_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
wasm_exporttype_t* export_type = export_types.data[3];
|
||||||
|
|
||||||
|
const wasm_name_t* export_name = wasm_exporttype_name(export_type);
|
||||||
|
wasmer_assert_name(export_name, "memory");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_exporttype_type(export_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_MEMORY);
|
||||||
|
|
||||||
|
const wasm_memorytype_t* memory_type = wasm_externtype_as_memorytype_const(extern_type);
|
||||||
|
const wasm_limits_t* memory_limits = wasm_memorytype_limits(memory_type);
|
||||||
|
assert(memory_limits->min == 1);
|
||||||
|
assert(memory_limits->max == wasm_limits_max_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_exporttype_vec_delete(&export_types);
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_imports() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(
|
||||||
|
&wat,
|
||||||
|
"(module\n"
|
||||||
|
" (import \"ns\" \"function\" (func))\n"
|
||||||
|
" (import \"ns\" \"global\" (global f32))\n"
|
||||||
|
" (import \"ns\" \"table\" (table 1 2 anyfunc))\n"
|
||||||
|
" (import \"ns\" \"memory\" (memory 3 4)))"
|
||||||
|
);
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
wasm_module_t* module = wasm_module_new(store, wasm);
|
||||||
|
assert(module);
|
||||||
|
|
||||||
|
wasm_importtype_vec_t import_types;
|
||||||
|
wasm_module_imports(module, &import_types);
|
||||||
|
|
||||||
|
assert(import_types.size == 4);
|
||||||
|
|
||||||
|
{
|
||||||
|
const wasm_importtype_t* import_type = import_types.data[0];
|
||||||
|
|
||||||
|
const wasm_name_t* import_module = wasm_importtype_module(import_type);
|
||||||
|
wasmer_assert_name(import_module, "ns");
|
||||||
|
|
||||||
|
const wasm_name_t* import_name = wasm_importtype_name(import_type);
|
||||||
|
wasmer_assert_name(import_name, "function");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_importtype_type(import_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_FUNC);
|
||||||
|
|
||||||
|
const wasm_functype_t* func_type = wasm_externtype_as_functype_const(extern_type);
|
||||||
|
|
||||||
|
const wasm_valtype_vec_t* func_params = wasm_functype_params(func_type);
|
||||||
|
assert(func_params && func_params->size == 0);
|
||||||
|
|
||||||
|
const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type);
|
||||||
|
assert(func_results && func_results->size == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const wasm_importtype_t* import_type = import_types.data[1];
|
||||||
|
|
||||||
|
const wasm_name_t* import_module = wasm_importtype_module(import_type);
|
||||||
|
wasmer_assert_name(import_module, "ns");
|
||||||
|
|
||||||
|
const wasm_name_t* import_name = wasm_importtype_name(import_type);
|
||||||
|
wasmer_assert_name(import_name, "global");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_importtype_type(import_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_GLOBAL);
|
||||||
|
|
||||||
|
const wasm_globaltype_t* global_type = wasm_externtype_as_globaltype_const(extern_type);
|
||||||
|
assert(wasm_valtype_kind(wasm_globaltype_content(global_type)) == WASM_F32);
|
||||||
|
assert(wasm_globaltype_mutability(global_type) == WASM_CONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const wasm_importtype_t* import_type = import_types.data[2];
|
||||||
|
|
||||||
|
const wasm_name_t* import_module = wasm_importtype_module(import_type);
|
||||||
|
wasmer_assert_name(import_module, "ns");
|
||||||
|
|
||||||
|
const wasm_name_t* import_name = wasm_importtype_name(import_type);
|
||||||
|
wasmer_assert_name(import_name, "table");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_importtype_type(import_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_TABLE);
|
||||||
|
|
||||||
|
const wasm_tabletype_t* table_type = wasm_externtype_as_tabletype_const(extern_type);
|
||||||
|
assert(wasm_valtype_kind(wasm_tabletype_element(table_type)) == WASM_FUNCREF);
|
||||||
|
|
||||||
|
const wasm_limits_t* table_limits = wasm_tabletype_limits(table_type);
|
||||||
|
assert(table_limits->min == 1);
|
||||||
|
assert(table_limits->max == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const wasm_importtype_t* import_type = import_types.data[3];
|
||||||
|
|
||||||
|
const wasm_name_t* import_module = wasm_importtype_module(import_type);
|
||||||
|
wasmer_assert_name(import_module, "ns");
|
||||||
|
|
||||||
|
const wasm_name_t* import_name = wasm_importtype_name(import_type);
|
||||||
|
wasmer_assert_name(import_name, "memory");
|
||||||
|
|
||||||
|
const wasm_externtype_t* extern_type = wasm_importtype_type(import_type);
|
||||||
|
assert(wasm_externtype_kind(extern_type) == WASM_EXTERN_MEMORY);
|
||||||
|
|
||||||
|
const wasm_memorytype_t* memory_type = wasm_externtype_as_memorytype_const(extern_type);
|
||||||
|
const wasm_limits_t* memory_limits = wasm_memorytype_limits(memory_type);
|
||||||
|
assert(memory_limits->min == 3);
|
||||||
|
assert(memory_limits->max == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_importtype_vec_delete(&import_types);
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_serialize() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(&wat, "(module)");
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
wasm_module_t* module = wasm_module_new(store, wasm);
|
||||||
|
assert(module);
|
||||||
|
|
||||||
|
wasm_byte_vec_t serialized_module;
|
||||||
|
wasm_module_serialize(module, &serialized_module);
|
||||||
|
assert(serialized_module.size > 0);
|
||||||
|
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_byte_vec_delete(&serialized_module);
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_serialize_and_deserialize() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(
|
||||||
|
&wat,
|
||||||
|
"(module\n"
|
||||||
|
" (func (export \"function\") (param i32 i64))\n"
|
||||||
|
" (global (export \"global\") i32 (i32.const 7))\n"
|
||||||
|
" (table (export \"table\") 0 funcref)\n"
|
||||||
|
" (memory (export \"memory\") 1))"
|
||||||
|
);
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
wasm_module_t* module = wasm_module_new(store, wasm);
|
||||||
|
assert(module);
|
||||||
|
|
||||||
|
wasm_byte_vec_t serialized_module;
|
||||||
|
wasm_module_serialize(module, &serialized_module);
|
||||||
|
assert(serialized_module.size > 0);
|
||||||
|
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_module_t* deserialized_module = wasm_module_deserialize(
|
||||||
|
store,
|
||||||
|
&serialized_module
|
||||||
|
);
|
||||||
|
wasm_byte_vec_delete(&serialized_module);
|
||||||
|
assert(deserialized_module);
|
||||||
|
|
||||||
|
wasm_exporttype_vec_t export_types;
|
||||||
|
wasm_module_exports(deserialized_module, &export_types);
|
||||||
|
|
||||||
|
assert(export_types.size == 4);
|
||||||
|
|
||||||
|
wasm_exporttype_vec_delete(&export_types);
|
||||||
|
wasm_module_delete(deserialized_module);
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use super::engine::wasm_engine_t;
|
use super::engine::wasm_engine_t;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use wasmer::Store;
|
use wasmer::Store;
|
||||||
|
|
||||||
/// Opaque wrapper around `Store`
|
/// Opaque wrapper around `Store`
|
||||||
@@ -10,11 +9,10 @@ pub struct wasm_store_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_store_new(
|
pub unsafe extern "C" fn wasm_store_new(
|
||||||
wasm_engine_ptr: Option<NonNull<wasm_engine_t>>,
|
engine: Option<&wasm_engine_t>,
|
||||||
) -> Option<Box<wasm_store_t>> {
|
) -> Option<Box<wasm_store_t>> {
|
||||||
let wasm_engine_ptr = wasm_engine_ptr?;
|
let engine = engine?;
|
||||||
let wasm_engine = wasm_engine_ptr.as_ref();
|
let store = Store::new(&*engine.inner);
|
||||||
let store = Store::new(&*wasm_engine.inner);
|
|
||||||
|
|
||||||
Some(Box::new(wasm_store_t { inner: store }))
|
Some(Box::new(wasm_store_t { inner: store }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use super::store::wasm_store_t;
|
use super::store::wasm_store_t;
|
||||||
use super::types::{wasm_byte_vec_t, wasm_frame_t, wasm_frame_vec_t, wasm_message_t};
|
use super::types::{wasm_byte_vec_t, wasm_frame_t, wasm_frame_vec_t, wasm_message_t};
|
||||||
|
use std::str;
|
||||||
use wasmer::RuntimeError;
|
use wasmer::RuntimeError;
|
||||||
|
|
||||||
// opaque type which is a `RuntimeError`
|
// opaque type which is a `RuntimeError`
|
||||||
@@ -19,8 +20,8 @@ pub unsafe extern "C" fn wasm_trap_new(
|
|||||||
_store: &mut wasm_store_t,
|
_store: &mut wasm_store_t,
|
||||||
message: &wasm_message_t,
|
message: &wasm_message_t,
|
||||||
) -> Option<Box<wasm_trap_t>> {
|
) -> Option<Box<wasm_trap_t>> {
|
||||||
let message_bytes: &[u8] = message.into_slice()?;
|
let message_bytes = message.into_slice()?;
|
||||||
let message_str = c_try!(std::str::from_utf8(message_bytes));
|
let message_str = c_try!(str::from_utf8(message_bytes));
|
||||||
let runtime_error = RuntimeError::new(message_str);
|
let runtime_error = RuntimeError::new(message_str);
|
||||||
let trap = runtime_error.into();
|
let trap = runtime_error.into();
|
||||||
|
|
||||||
@@ -31,11 +32,16 @@ pub unsafe extern "C" fn wasm_trap_new(
|
|||||||
pub unsafe extern "C" fn wasm_trap_delete(_trap: Option<Box<wasm_trap_t>>) {}
|
pub unsafe extern "C" fn wasm_trap_delete(_trap: Option<Box<wasm_trap_t>>) {}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out_ptr: &mut wasm_byte_vec_t) {
|
pub unsafe extern "C" fn wasm_trap_message(
|
||||||
|
trap: &wasm_trap_t,
|
||||||
|
// own
|
||||||
|
out: &mut wasm_byte_vec_t,
|
||||||
|
) {
|
||||||
let message = trap.inner.message();
|
let message = trap.inner.message();
|
||||||
let byte_vec: wasm_byte_vec_t = message.into_bytes().into();
|
let byte_vec: wasm_byte_vec_t = message.into_bytes().into();
|
||||||
out_ptr.size = byte_vec.size;
|
|
||||||
out_ptr.data = byte_vec.data;
|
out.size = byte_vec.size;
|
||||||
|
out.data = byte_vec.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -44,10 +50,14 @@ pub unsafe extern "C" fn wasm_trap_origin(trap: &wasm_trap_t) -> Option<Box<wasm
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_trap_trace(trap: &wasm_trap_t, out_ptr: &mut wasm_frame_vec_t) {
|
pub unsafe extern "C" fn wasm_trap_trace(
|
||||||
|
trap: &wasm_trap_t,
|
||||||
|
// own
|
||||||
|
out: &mut wasm_frame_vec_t,
|
||||||
|
) {
|
||||||
let frames = trap.inner.trace();
|
let frames = trap.inner.trace();
|
||||||
let frame_vec: wasm_frame_vec_t = frames.into();
|
let frame_vec: wasm_frame_vec_t = frames.into();
|
||||||
|
|
||||||
out_ptr.size = frame_vec.size;
|
out.size = frame_vec.size;
|
||||||
out_ptr.data = frame_vec.data;
|
out.data = frame_vec.data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,37 @@
|
|||||||
use super::{wasm_externtype_t, wasm_name_t};
|
use super::{wasm_externtype_t, wasm_name_t};
|
||||||
use std::ptr::NonNull;
|
|
||||||
use wasmer::ExportType;
|
use wasmer::ExportType;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub struct wasm_exporttype_t {
|
pub struct wasm_exporttype_t {
|
||||||
name: NonNull<wasm_name_t>,
|
name: Box<wasm_name_t>,
|
||||||
extern_type: NonNull<wasm_externtype_t>,
|
extern_type: Box<wasm_externtype_t>,
|
||||||
|
|
||||||
/// If `true`, `name` and `extern_type` will be dropped by
|
|
||||||
/// `wasm_exporttype_t::drop`.
|
|
||||||
owns_fields: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_declare_boxed_vec!(exporttype);
|
wasm_declare_boxed_vec!(exporttype);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_exporttype_new(
|
pub extern "C" fn wasm_exporttype_new(
|
||||||
name: NonNull<wasm_name_t>,
|
name: Option<Box<wasm_name_t>>,
|
||||||
extern_type: NonNull<wasm_externtype_t>,
|
extern_type: Option<Box<wasm_externtype_t>>,
|
||||||
) -> Box<wasm_exporttype_t> {
|
) -> Option<Box<wasm_exporttype_t>> {
|
||||||
Box::new(wasm_exporttype_t {
|
Some(Box::new(wasm_exporttype_t {
|
||||||
name,
|
name: name?,
|
||||||
extern_type,
|
extern_type: extern_type?,
|
||||||
owns_fields: false,
|
}))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_exporttype_name(et: &'static wasm_exporttype_t) -> &'static wasm_name_t {
|
pub extern "C" fn wasm_exporttype_name(export_type: &wasm_exporttype_t) -> &wasm_name_t {
|
||||||
unsafe { et.name.as_ref() }
|
export_type.name.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_exporttype_type(
|
pub extern "C" fn wasm_exporttype_type(export_type: &wasm_exporttype_t) -> &wasm_externtype_t {
|
||||||
et: &'static wasm_exporttype_t,
|
export_type.extern_type.as_ref()
|
||||||
) -> &'static wasm_externtype_t {
|
|
||||||
unsafe { et.extern_type.as_ref() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_exporttype_delete(_exporttype: Option<Box<wasm_exporttype_t>>) {}
|
pub extern "C" fn wasm_exporttype_delete(_export_type: Option<Box<wasm_exporttype_t>>) {}
|
||||||
|
|
||||||
impl Drop for wasm_exporttype_t {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if self.owns_fields {
|
|
||||||
// SAFETY: `owns_fields` is set to `true` only in
|
|
||||||
// `wasm_exporttype_t::from(&ExportType)`, where the data
|
|
||||||
// are leaked properly and won't be freed somewhere else.
|
|
||||||
unsafe {
|
|
||||||
let _ = Box::from_raw(self.name.as_ptr());
|
|
||||||
let _ = Box::from_raw(self.extern_type.as_ptr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ExportType> for wasm_exporttype_t {
|
impl From<ExportType> for wasm_exporttype_t {
|
||||||
fn from(other: ExportType) -> Self {
|
fn from(other: ExportType) -> Self {
|
||||||
@@ -63,7 +41,6 @@ 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 {
|
||||||
// TODO: double check that freeing String as `Vec<u8>` is valid
|
|
||||||
let name = {
|
let name = {
|
||||||
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
|
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
|
||||||
let char_ptr = heap_str.as_mut_ptr();
|
let char_ptr = heap_str.as_mut_ptr();
|
||||||
@@ -73,18 +50,12 @@ impl From<&ExportType> for wasm_exporttype_t {
|
|||||||
data: char_ptr,
|
data: char_ptr,
|
||||||
};
|
};
|
||||||
Box::leak(heap_str);
|
Box::leak(heap_str);
|
||||||
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) }
|
|
||||||
|
Box::new(name_inner)
|
||||||
};
|
};
|
||||||
|
|
||||||
let extern_type = {
|
let extern_type = Box::new(other.ty().into());
|
||||||
let extern_type: wasm_externtype_t = other.ty().into();
|
|
||||||
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) }
|
|
||||||
};
|
|
||||||
|
|
||||||
wasm_exporttype_t {
|
wasm_exporttype_t { name, extern_type }
|
||||||
name,
|
|
||||||
extern_type,
|
|
||||||
owns_fields: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,13 @@
|
|||||||
use super::super::externals::wasm_extern_t;
|
use super::super::externals::wasm_extern_t;
|
||||||
use super::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t};
|
use super::{
|
||||||
|
wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t, WasmFunctionType,
|
||||||
|
WasmGlobalType, WasmMemoryType, WasmTableType,
|
||||||
|
};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmer::ExternType;
|
use wasmer::ExternType;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct wasm_externtype_t {
|
|
||||||
pub(crate) inner: ExternType,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
|
||||||
Box::new(wasm_externtype_t {
|
|
||||||
inner: e.inner.ty(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_externtype_delete(_et: Option<Box<wasm_externtype_t>>) {}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn wasm_externtype_copy(
|
|
||||||
wasm_externtype: &wasm_externtype_t,
|
|
||||||
) -> Box<wasm_externtype_t> {
|
|
||||||
Box::new(wasm_externtype_t {
|
|
||||||
inner: wasm_externtype.inner.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ExternType> for wasm_externtype_t {
|
|
||||||
fn from(other: ExternType) -> Self {
|
|
||||||
Self { inner: other }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&ExternType> for wasm_externtype_t {
|
|
||||||
fn from(other: &ExternType) -> Self {
|
|
||||||
other.clone().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
type wasm_externkind_t = u8;
|
type wasm_externkind_t = u8;
|
||||||
|
|
||||||
@@ -54,11 +20,6 @@ pub enum wasm_externkind_enum {
|
|||||||
WASM_EXTERN_MEMORY = 3,
|
WASM_EXTERN_MEMORY = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
|
|
||||||
wasm_externkind_enum::from(e.inner.ty()) as wasm_externkind_t
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ExternType> for wasm_externkind_enum {
|
impl From<ExternType> for wasm_externkind_enum {
|
||||||
fn from(other: ExternType) -> Self {
|
fn from(other: ExternType) -> Self {
|
||||||
(&other).into()
|
(&other).into()
|
||||||
@@ -75,9 +36,81 @@ impl From<&ExternType> for wasm_externkind_enum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum WasmExternType {
|
||||||
|
Function(WasmFunctionType),
|
||||||
|
Global(WasmGlobalType),
|
||||||
|
Table(WasmTableType),
|
||||||
|
Memory(WasmMemoryType),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct wasm_externtype_t {
|
||||||
|
pub(crate) inner: WasmExternType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl wasm_externtype_t {
|
||||||
|
pub(crate) fn new(extern_type: ExternType) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: match extern_type {
|
||||||
|
ExternType::Function(function_type) => {
|
||||||
|
WasmExternType::Function(WasmFunctionType::new(function_type))
|
||||||
|
}
|
||||||
|
ExternType::Global(global_type) => {
|
||||||
|
WasmExternType::Global(WasmGlobalType::new(global_type))
|
||||||
|
}
|
||||||
|
ExternType::Table(table_type) => {
|
||||||
|
WasmExternType::Table(WasmTableType::new(table_type))
|
||||||
|
}
|
||||||
|
ExternType::Memory(memory_type) => {
|
||||||
|
WasmExternType::Memory(WasmMemoryType::new(memory_type))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ExternType> for wasm_externtype_t {
|
||||||
|
fn from(extern_type: ExternType) -> Self {
|
||||||
|
Self::new(extern_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ExternType> for wasm_externtype_t {
|
||||||
|
fn from(other: &ExternType) -> Self {
|
||||||
|
other.clone().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t {
|
pub unsafe extern "C" fn wasm_extern_type(r#extern: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
||||||
wasm_externkind_enum::from(&et.inner) as wasm_externkind_t
|
Box::new(wasm_externtype_t::new(r#extern.inner.ty()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_externtype_delete(_extern_type: Option<Box<wasm_externtype_t>>) {}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wasm_externtype_copy(extern_type: &wasm_externtype_t) -> Box<wasm_externtype_t> {
|
||||||
|
Box::new(extern_type.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_externtype_kind(
|
||||||
|
extern_type: &wasm_externtype_t,
|
||||||
|
) -> wasm_externkind_t {
|
||||||
|
(match extern_type.inner {
|
||||||
|
WasmExternType::Function(_) => wasm_externkind_enum::WASM_EXTERN_FUNC,
|
||||||
|
WasmExternType::Global(_) => wasm_externkind_enum::WASM_EXTERN_GLOBAL,
|
||||||
|
WasmExternType::Table(_) => wasm_externkind_enum::WASM_EXTERN_TABLE,
|
||||||
|
WasmExternType::Memory(_) => wasm_externkind_enum::WASM_EXTERN_MEMORY,
|
||||||
|
}) as wasm_externkind_t
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Error)]
|
#[derive(Debug, Clone, Error)]
|
||||||
@@ -94,7 +127,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_functype_t {
|
|||||||
type Error = ExternTypeConversionError;
|
type Error = ExternTypeConversionError;
|
||||||
|
|
||||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||||
if let ExternType::Function(_) = other.inner {
|
if let WasmExternType::Function(_) = other.inner {
|
||||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||||
} else {
|
} else {
|
||||||
Err(ExternTypeConversionError("Wrong type: expected function"))
|
Err(ExternTypeConversionError("Wrong type: expected function"))
|
||||||
@@ -106,7 +139,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
|
|||||||
type Error = ExternTypeConversionError;
|
type Error = ExternTypeConversionError;
|
||||||
|
|
||||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||||
if let ExternType::Global(_) = other.inner {
|
if let WasmExternType::Global(_) = other.inner {
|
||||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||||
} else {
|
} else {
|
||||||
Err(ExternTypeConversionError("Wrong type: expected global"))
|
Err(ExternTypeConversionError("Wrong type: expected global"))
|
||||||
@@ -114,23 +147,11 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t {
|
|
||||||
type Error = ExternTypeConversionError;
|
|
||||||
|
|
||||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
|
||||||
if let ExternType::Memory(_) = other.inner {
|
|
||||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
|
||||||
} else {
|
|
||||||
Err(ExternTypeConversionError("Wrong type: expected memory"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
|
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
|
||||||
type Error = ExternTypeConversionError;
|
type Error = ExternTypeConversionError;
|
||||||
|
|
||||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||||
if let ExternType::Table(_) = other.inner {
|
if let WasmExternType::Table(_) = other.inner {
|
||||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||||
} else {
|
} else {
|
||||||
Err(ExternTypeConversionError("Wrong type: expected table"))
|
Err(ExternTypeConversionError("Wrong type: expected table"))
|
||||||
@@ -138,114 +159,126 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t {
|
||||||
|
type Error = ExternTypeConversionError;
|
||||||
|
|
||||||
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||||
|
if let WasmExternType::Memory(_) = other.inner {
|
||||||
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||||
|
} else {
|
||||||
|
Err(ExternTypeConversionError("Wrong type: expected memory"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_functype_const(
|
pub unsafe extern "C" fn wasm_externtype_as_functype_const(
|
||||||
et: &'static wasm_externtype_t,
|
extern_type: &'static wasm_externtype_t,
|
||||||
) -> Option<&'static wasm_functype_t> {
|
) -> Option<&'static wasm_functype_t> {
|
||||||
Some(c_try!(et.try_into()))
|
Some(c_try!(extern_type.try_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_functype(
|
pub unsafe extern "C" fn wasm_externtype_as_functype(
|
||||||
et: &'static wasm_externtype_t,
|
extern_type: &'static wasm_externtype_t,
|
||||||
) -> Option<&'static wasm_functype_t> {
|
) -> Option<&'static wasm_functype_t> {
|
||||||
Some(c_try!(et.try_into()))
|
Some(c_try!(extern_type.try_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_as_externtype_const(
|
pub unsafe extern "C" fn wasm_functype_as_externtype_const(
|
||||||
ft: &'static wasm_functype_t,
|
function_type: &'static wasm_functype_t,
|
||||||
) -> &'static wasm_externtype_t {
|
) -> &'static wasm_externtype_t {
|
||||||
&ft.extern_
|
&function_type.extern_type
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_as_externtype(
|
pub unsafe extern "C" fn wasm_functype_as_externtype(
|
||||||
ft: &'static wasm_functype_t,
|
function_type: &'static wasm_functype_t,
|
||||||
) -> &'static wasm_externtype_t {
|
) -> &'static wasm_externtype_t {
|
||||||
&ft.extern_
|
&function_type.extern_type
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_memorytype_const(
|
|
||||||
et: &'static wasm_externtype_t,
|
|
||||||
) -> Option<&'static wasm_memorytype_t> {
|
|
||||||
Some(c_try!(et.try_into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_memorytype(
|
|
||||||
et: &'static wasm_externtype_t,
|
|
||||||
) -> Option<&'static wasm_memorytype_t> {
|
|
||||||
Some(c_try!(et.try_into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_memorytype_as_externtype_const(
|
|
||||||
mt: &'static wasm_memorytype_t,
|
|
||||||
) -> &'static wasm_externtype_t {
|
|
||||||
&mt.extern_
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_memorytype_as_externtype(
|
|
||||||
mt: &'static wasm_memorytype_t,
|
|
||||||
) -> &'static wasm_externtype_t {
|
|
||||||
&mt.extern_
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_globaltype_const(
|
pub unsafe extern "C" fn wasm_externtype_as_globaltype_const(
|
||||||
et: &'static wasm_externtype_t,
|
extern_type: &'static wasm_externtype_t,
|
||||||
) -> Option<&'static wasm_globaltype_t> {
|
) -> Option<&'static wasm_globaltype_t> {
|
||||||
Some(c_try!(et.try_into()))
|
Some(c_try!(extern_type.try_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_globaltype(
|
pub unsafe extern "C" fn wasm_externtype_as_globaltype(
|
||||||
et: &'static wasm_externtype_t,
|
extern_type: &'static wasm_externtype_t,
|
||||||
) -> Option<&'static wasm_globaltype_t> {
|
) -> Option<&'static wasm_globaltype_t> {
|
||||||
Some(c_try!(et.try_into()))
|
Some(c_try!(extern_type.try_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_globaltype_as_externtype_const(
|
pub unsafe extern "C" fn wasm_globaltype_as_externtype_const(
|
||||||
gt: &'static wasm_globaltype_t,
|
global_type: &'static wasm_globaltype_t,
|
||||||
) -> &'static wasm_externtype_t {
|
) -> &'static wasm_externtype_t {
|
||||||
>.extern_
|
&global_type.extern_type
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_globaltype_as_externtype(
|
pub unsafe extern "C" fn wasm_globaltype_as_externtype(
|
||||||
gt: &'static wasm_globaltype_t,
|
global_type: &'static wasm_globaltype_t,
|
||||||
) -> &'static wasm_externtype_t {
|
) -> &'static wasm_externtype_t {
|
||||||
>.extern_
|
&global_type.extern_type
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_tabletype_const(
|
pub unsafe extern "C" fn wasm_externtype_as_tabletype_const(
|
||||||
et: &'static wasm_externtype_t,
|
extern_type: &'static wasm_externtype_t,
|
||||||
) -> Option<&'static wasm_tabletype_t> {
|
) -> Option<&'static wasm_tabletype_t> {
|
||||||
Some(c_try!(et.try_into()))
|
Some(c_try!(extern_type.try_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_externtype_as_tabletype(
|
pub unsafe extern "C" fn wasm_externtype_as_tabletype(
|
||||||
et: &'static wasm_externtype_t,
|
extern_type: &'static wasm_externtype_t,
|
||||||
) -> Option<&'static wasm_tabletype_t> {
|
) -> Option<&'static wasm_tabletype_t> {
|
||||||
Some(c_try!(et.try_into()))
|
Some(c_try!(extern_type.try_into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_tabletype_as_externtype_const(
|
pub unsafe extern "C" fn wasm_tabletype_as_externtype_const(
|
||||||
tt: &'static wasm_tabletype_t,
|
table_type: &'static wasm_tabletype_t,
|
||||||
) -> &'static wasm_externtype_t {
|
) -> &'static wasm_externtype_t {
|
||||||
&tt.extern_
|
&table_type.extern_type
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_tabletype_as_externtype(
|
pub unsafe extern "C" fn wasm_tabletype_as_externtype(
|
||||||
tt: &'static wasm_tabletype_t,
|
table_type: &'static wasm_tabletype_t,
|
||||||
) -> &'static wasm_externtype_t {
|
) -> &'static wasm_externtype_t {
|
||||||
&tt.extern_
|
&table_type.extern_type
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_externtype_as_memorytype_const(
|
||||||
|
extern_type: &'static wasm_externtype_t,
|
||||||
|
) -> Option<&'static wasm_memorytype_t> {
|
||||||
|
Some(c_try!(extern_type.try_into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_externtype_as_memorytype(
|
||||||
|
extern_type: &'static wasm_externtype_t,
|
||||||
|
) -> Option<&'static wasm_memorytype_t> {
|
||||||
|
Some(c_try!(extern_type.try_into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_memorytype_as_externtype_const(
|
||||||
|
memory_type: &'static wasm_memorytype_t,
|
||||||
|
) -> &'static wasm_externtype_t {
|
||||||
|
&memory_type.extern_type
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_memorytype_as_externtype(
|
||||||
|
memory_type: &'static wasm_memorytype_t,
|
||||||
|
) -> &'static wasm_externtype_t {
|
||||||
|
&memory_type.extern_type
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,91 @@
|
|||||||
use super::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t};
|
use super::{
|
||||||
|
wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_delete, wasm_valtype_vec_t, WasmExternType,
|
||||||
|
};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use wasmer::{ExternType, FunctionType, ValType};
|
use wasmer::{ExternType, FunctionType, ValType};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct WasmFunctionType {
|
||||||
|
pub(crate) function_type: FunctionType,
|
||||||
|
params: Box<wasm_valtype_vec_t>,
|
||||||
|
results: Box<wasm_valtype_vec_t>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmFunctionType {
|
||||||
|
pub(crate) fn new(function_type: FunctionType) -> Self {
|
||||||
|
let params = {
|
||||||
|
let mut valtypes = function_type
|
||||||
|
.params()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(Into::into)
|
||||||
|
.map(Box::new)
|
||||||
|
.map(Box::into_raw)
|
||||||
|
.collect::<Vec<*mut wasm_valtype_t>>();
|
||||||
|
|
||||||
|
let valtypes_vec = Box::new(wasm_valtype_vec_t {
|
||||||
|
size: valtypes.len(),
|
||||||
|
data: valtypes.as_mut_ptr(),
|
||||||
|
});
|
||||||
|
|
||||||
|
mem::forget(valtypes);
|
||||||
|
|
||||||
|
valtypes_vec
|
||||||
|
};
|
||||||
|
let results = {
|
||||||
|
let mut valtypes = function_type
|
||||||
|
.results()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(Into::into)
|
||||||
|
.map(Box::new)
|
||||||
|
.map(Box::into_raw)
|
||||||
|
.collect::<Vec<*mut wasm_valtype_t>>();
|
||||||
|
|
||||||
|
let valtypes_vec = Box::new(wasm_valtype_vec_t {
|
||||||
|
size: valtypes.len(),
|
||||||
|
data: valtypes.as_mut_ptr(),
|
||||||
|
});
|
||||||
|
|
||||||
|
mem::forget(valtypes);
|
||||||
|
|
||||||
|
valtypes_vec
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
function_type,
|
||||||
|
params,
|
||||||
|
results,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for WasmFunctionType {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self::new(self.function_type.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct wasm_functype_t {
|
pub struct wasm_functype_t {
|
||||||
pub(crate) extern_: wasm_externtype_t,
|
pub(crate) extern_type: wasm_externtype_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wasm_functype_t {
|
impl wasm_functype_t {
|
||||||
pub(crate) fn sig(&self) -> &FunctionType {
|
pub(crate) fn new(function_type: FunctionType) -> Self {
|
||||||
if let ExternType::Function(ref f) = self.extern_.inner {
|
Self {
|
||||||
f
|
extern_type: wasm_externtype_t::new(ExternType::Function(function_type)),
|
||||||
} else {
|
|
||||||
unreachable!("data corruption: `wasm_functype_t` does not contain a function")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(function_type: FunctionType) -> Self {
|
pub(crate) fn inner(&self) -> &WasmFunctionType {
|
||||||
Self {
|
match &self.extern_type.inner {
|
||||||
extern_: wasm_externtype_t {
|
WasmExternType::Function(wasm_function_type) => &wasm_function_type,
|
||||||
inner: ExternType::Function(function_type),
|
_ => {
|
||||||
},
|
unreachable!("Data corruption: `wasm_functype_t` does not contain a function type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,88 +94,60 @@ wasm_declare_vec!(functype);
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_new(
|
pub unsafe extern "C" fn wasm_functype_new(
|
||||||
// own
|
params: Option<Box<wasm_valtype_vec_t>>,
|
||||||
params: Option<NonNull<wasm_valtype_vec_t>>,
|
results: Option<Box<wasm_valtype_vec_t>>,
|
||||||
// own
|
|
||||||
results: Option<NonNull<wasm_valtype_vec_t>>,
|
|
||||||
) -> Option<Box<wasm_functype_t>> {
|
) -> Option<Box<wasm_functype_t>> {
|
||||||
wasm_functype_new_inner(params?, results?)
|
let params = params?;
|
||||||
}
|
let results = results?;
|
||||||
|
|
||||||
unsafe fn wasm_functype_new_inner(
|
let params_as_valtype: Vec<ValType> = params
|
||||||
// own
|
.into_slice()?
|
||||||
params: NonNull<wasm_valtype_vec_t>,
|
.into_iter()
|
||||||
// own
|
.map(|val| val.as_ref().into())
|
||||||
results: NonNull<wasm_valtype_vec_t>,
|
.collect::<Vec<_>>();
|
||||||
) -> Option<Box<wasm_functype_t>> {
|
let results_as_valtype: Vec<ValType> = results
|
||||||
let params = params.as_ref();
|
|
||||||
let results = results.as_ref();
|
|
||||||
let params: Vec<ValType> = params
|
|
||||||
.into_slice()?
|
.into_slice()?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ptr| **ptr)
|
.map(|val| val.as_ref().into())
|
||||||
.map(Into::into)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let results: Vec<ValType> = results
|
|
||||||
.into_slice()?
|
|
||||||
.iter()
|
|
||||||
.map(|ptr| **ptr)
|
|
||||||
.map(Into::into)
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
wasm_valtype_vec_delete(Box::into_raw(params));
|
||||||
|
wasm_valtype_vec_delete(Box::into_raw(results));
|
||||||
|
|
||||||
Some(Box::new(wasm_functype_t::new(FunctionType::new(
|
Some(Box::new(wasm_functype_t::new(FunctionType::new(
|
||||||
params, results,
|
params_as_valtype,
|
||||||
|
results_as_valtype,
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_delete(_ft: Option<Box<wasm_functype_t>>) {}
|
pub unsafe extern "C" fn wasm_functype_delete(_function_type: Option<Box<wasm_functype_t>>) {}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_copy(
|
pub unsafe extern "C" fn wasm_functype_copy(
|
||||||
arg: Option<NonNull<wasm_functype_t>>,
|
function_type: Option<&wasm_functype_t>,
|
||||||
) -> Option<Box<wasm_functype_t>> {
|
) -> Option<Box<wasm_functype_t>> {
|
||||||
let arg = arg?;
|
let function_type = function_type?;
|
||||||
let funcsig = arg.as_ref();
|
|
||||||
Some(Box::new(funcsig.clone()))
|
Some(Box::new(wasm_functype_t::new(
|
||||||
|
function_type.inner().function_type.clone(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix memory leak
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
|
pub unsafe extern "C" fn wasm_functype_params(
|
||||||
let mut valtypes = ft
|
function_type: Option<&wasm_functype_t>,
|
||||||
.sig()
|
) -> Option<&wasm_valtype_vec_t> {
|
||||||
.params()
|
let function_type = function_type?;
|
||||||
.iter()
|
|
||||||
.cloned()
|
Some(function_type.inner().params.as_ref())
|
||||||
.map(Into::into)
|
|
||||||
.map(Box::new)
|
|
||||||
.map(Box::into_raw)
|
|
||||||
.collect::<Vec<*mut wasm_valtype_t>>();
|
|
||||||
let out = Box::into_raw(Box::new(wasm_valtype_vec_t {
|
|
||||||
size: valtypes.len(),
|
|
||||||
data: valtypes.as_mut_ptr(),
|
|
||||||
}));
|
|
||||||
mem::forget(valtypes);
|
|
||||||
out as *const _
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix memory leak
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
|
pub unsafe extern "C" fn wasm_functype_results(
|
||||||
let mut valtypes = ft
|
function_type: Option<&wasm_functype_t>,
|
||||||
.sig()
|
) -> Option<&wasm_valtype_vec_t> {
|
||||||
.results()
|
let function_type = function_type?;
|
||||||
.iter()
|
|
||||||
.cloned()
|
Some(function_type.inner().results.as_ref())
|
||||||
.map(Into::into)
|
|
||||||
.map(Box::new)
|
|
||||||
.map(Box::into_raw)
|
|
||||||
.collect::<Vec<*mut wasm_valtype_t>>();
|
|
||||||
let out = Box::into_raw(Box::new(wasm_valtype_vec_t {
|
|
||||||
size: valtypes.len(),
|
|
||||||
data: valtypes.as_mut_ptr(),
|
|
||||||
}));
|
|
||||||
mem::forget(valtypes);
|
|
||||||
out as *const _
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,47 @@
|
|||||||
use super::{
|
use super::{
|
||||||
wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete, wasm_valtype_t,
|
wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete,
|
||||||
|
wasm_valtype_t, WasmExternType,
|
||||||
};
|
};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use wasmer::{ExternType, GlobalType};
|
use wasmer::{ExternType, GlobalType};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct WasmGlobalType {
|
||||||
|
pub(crate) global_type: GlobalType,
|
||||||
|
content: Box<wasm_valtype_t>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmGlobalType {
|
||||||
|
pub(crate) fn new(global_type: GlobalType) -> Self {
|
||||||
|
let content = Box::new(global_type.ty.into());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
global_type,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct wasm_globaltype_t {
|
pub struct wasm_globaltype_t {
|
||||||
pub(crate) extern_: wasm_externtype_t,
|
pub(crate) extern_type: wasm_externtype_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wasm_globaltype_t {
|
impl wasm_globaltype_t {
|
||||||
pub(crate) fn as_globaltype(&self) -> &GlobalType {
|
pub(crate) fn new(global_type: GlobalType) -> Self {
|
||||||
if let ExternType::Global(ref g) = self.extern_.inner {
|
Self {
|
||||||
g
|
extern_type: wasm_externtype_t::new(ExternType::Global(global_type)),
|
||||||
} else {
|
|
||||||
unreachable!(
|
|
||||||
"Data corruption detected: `wasm_globaltype_t` does not contain a `GlobalType`"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(global_type: GlobalType) -> Self {
|
pub(crate) fn inner(&self) -> &WasmGlobalType {
|
||||||
Self {
|
match &self.extern_type.inner {
|
||||||
extern_: wasm_externtype_t {
|
WasmExternType::Global(wasm_global_type) => &wasm_global_type,
|
||||||
inner: ExternType::Global(global_type),
|
_ => {
|
||||||
},
|
unreachable!("Data corruption: `wasm_globaltype_t` does not contain a global type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,45 +50,34 @@ wasm_declare_vec!(globaltype);
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_globaltype_new(
|
pub unsafe extern "C" fn wasm_globaltype_new(
|
||||||
// own
|
|
||||||
valtype: Option<Box<wasm_valtype_t>>,
|
valtype: Option<Box<wasm_valtype_t>>,
|
||||||
mutability: wasm_mutability_t,
|
mutability: wasm_mutability_t,
|
||||||
) -> Option<Box<wasm_globaltype_t>> {
|
) -> Option<Box<wasm_globaltype_t>> {
|
||||||
wasm_globaltype_new_inner(valtype?, mutability)
|
let valtype = valtype?;
|
||||||
|
let mutability: wasm_mutability_enum = mutability.try_into().ok()?;
|
||||||
|
let global_type = Box::new(wasm_globaltype_t::new(GlobalType::new(
|
||||||
|
(*valtype).into(),
|
||||||
|
mutability.into(),
|
||||||
|
)));
|
||||||
|
|
||||||
|
wasm_valtype_delete(Some(valtype));
|
||||||
|
|
||||||
|
Some(global_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: Option<Box<wasm_globaltype_t>>) {}
|
pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option<Box<wasm_globaltype_t>>) {}
|
||||||
|
|
||||||
unsafe fn wasm_globaltype_new_inner(
|
|
||||||
// own
|
|
||||||
valtype: Box<wasm_valtype_t>,
|
|
||||||
mutability: wasm_mutability_t,
|
|
||||||
) -> Option<Box<wasm_globaltype_t>> {
|
|
||||||
let me: wasm_mutability_enum = mutability.try_into().ok()?;
|
|
||||||
let gd = Box::new(wasm_globaltype_t::new(GlobalType::new(
|
|
||||||
(*valtype).into(),
|
|
||||||
me.into(),
|
|
||||||
)));
|
|
||||||
wasm_valtype_delete(Some(valtype));
|
|
||||||
|
|
||||||
Some(gd)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_globaltype_mutability(
|
pub unsafe extern "C" fn wasm_globaltype_mutability(
|
||||||
globaltype: &wasm_globaltype_t,
|
global_type: &wasm_globaltype_t,
|
||||||
) -> wasm_mutability_t {
|
) -> wasm_mutability_t {
|
||||||
let gt = globaltype.as_globaltype();
|
wasm_mutability_enum::from(global_type.inner().global_type.mutability).into()
|
||||||
wasm_mutability_enum::from(gt.mutability).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix memory leak
|
|
||||||
// this function leaks memory because the returned limits pointer is not owned
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_globaltype_content(
|
pub unsafe extern "C" fn wasm_globaltype_content(
|
||||||
globaltype: &wasm_globaltype_t,
|
global_type: &wasm_globaltype_t,
|
||||||
) -> *const wasm_valtype_t {
|
) -> &wasm_valtype_t {
|
||||||
let gt = globaltype.as_globaltype();
|
global_type.inner().content.as_ref()
|
||||||
Box::into_raw(Box::new(gt.ty.into()))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,45 @@
|
|||||||
use super::{wasm_externtype_t, wasm_name_t};
|
use super::{wasm_externtype_t, wasm_name_t};
|
||||||
use std::ptr::NonNull;
|
|
||||||
use wasmer::ImportType;
|
use wasmer::ImportType;
|
||||||
|
|
||||||
// TODO: improve ownership in `importtype_t` (can we safely use `Box<wasm_name_t>` here?)
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub struct wasm_importtype_t {
|
pub struct wasm_importtype_t {
|
||||||
pub(crate) module: NonNull<wasm_name_t>,
|
module: Box<wasm_name_t>,
|
||||||
pub(crate) name: NonNull<wasm_name_t>,
|
name: Box<wasm_name_t>,
|
||||||
pub(crate) extern_type: NonNull<wasm_externtype_t>,
|
extern_type: Box<wasm_externtype_t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_declare_boxed_vec!(importtype);
|
wasm_declare_boxed_vec!(importtype);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_new(
|
pub extern "C" fn wasm_importtype_new(
|
||||||
module: NonNull<wasm_name_t>,
|
module: Option<Box<wasm_name_t>>,
|
||||||
name: NonNull<wasm_name_t>,
|
name: Option<Box<wasm_name_t>>,
|
||||||
extern_type: NonNull<wasm_externtype_t>,
|
extern_type: Option<Box<wasm_externtype_t>>,
|
||||||
) -> Box<wasm_importtype_t> {
|
) -> Option<Box<wasm_importtype_t>> {
|
||||||
Box::new(wasm_importtype_t {
|
Some(Box::new(wasm_importtype_t {
|
||||||
name,
|
name: name?,
|
||||||
module,
|
module: module?,
|
||||||
extern_type,
|
extern_type: extern_type?,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_module(et: &'static wasm_importtype_t) -> &'static wasm_name_t {
|
pub extern "C" fn wasm_importtype_module(import_type: &wasm_importtype_t) -> &wasm_name_t {
|
||||||
unsafe { et.module.as_ref() }
|
import_type.module.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_name(et: &'static wasm_importtype_t) -> &'static wasm_name_t {
|
pub extern "C" fn wasm_importtype_name(import_type: &wasm_importtype_t) -> &wasm_name_t {
|
||||||
unsafe { et.name.as_ref() }
|
import_type.name.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_type(
|
pub extern "C" fn wasm_importtype_type(import_type: &wasm_importtype_t) -> &wasm_externtype_t {
|
||||||
et: &'static wasm_importtype_t,
|
import_type.extern_type.as_ref()
|
||||||
) -> &'static wasm_externtype_t {
|
|
||||||
unsafe { et.extern_type.as_ref() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_importtype_delete(_importtype: Option<Box<wasm_importtype_t>>) {}
|
pub unsafe extern "C" fn wasm_importtype_delete(_import_type: Option<Box<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 {
|
||||||
@@ -53,7 +49,19 @@ 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 {
|
||||||
// TODO: double check that freeing String as `Vec<u8>` is valid
|
let module = {
|
||||||
|
let mut heap_str: Box<str> = other.module().to_string().into_boxed_str();
|
||||||
|
let char_ptr = heap_str.as_mut_ptr();
|
||||||
|
let str_len = heap_str.bytes().len();
|
||||||
|
let module_inner = wasm_name_t {
|
||||||
|
size: str_len,
|
||||||
|
data: char_ptr,
|
||||||
|
};
|
||||||
|
Box::leak(heap_str);
|
||||||
|
|
||||||
|
Box::new(module_inner)
|
||||||
|
};
|
||||||
|
|
||||||
let name = {
|
let name = {
|
||||||
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
|
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
|
||||||
let char_ptr = heap_str.as_mut_ptr();
|
let char_ptr = heap_str.as_mut_ptr();
|
||||||
@@ -63,26 +71,11 @@ impl From<&ImportType> for wasm_importtype_t {
|
|||||||
data: char_ptr,
|
data: char_ptr,
|
||||||
};
|
};
|
||||||
Box::leak(heap_str);
|
Box::leak(heap_str);
|
||||||
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) }
|
|
||||||
|
Box::new(name_inner)
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: double check that freeing String as `Vec<u8>` is valid
|
let extern_type = Box::new(other.ty().into());
|
||||||
let module = {
|
|
||||||
let mut heap_str: Box<str> = other.module().to_string().into_boxed_str();
|
|
||||||
let char_ptr = heap_str.as_mut_ptr();
|
|
||||||
let str_len = heap_str.bytes().len();
|
|
||||||
let name_inner = wasm_name_t {
|
|
||||||
size: str_len,
|
|
||||||
data: char_ptr,
|
|
||||||
};
|
|
||||||
Box::leak(heap_str);
|
|
||||||
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) }
|
|
||||||
};
|
|
||||||
|
|
||||||
let extern_type = {
|
|
||||||
let extern_type: wasm_externtype_t = other.ty().into();
|
|
||||||
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) }
|
|
||||||
};
|
|
||||||
|
|
||||||
wasm_importtype_t {
|
wasm_importtype_t {
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -1,49 +1,58 @@
|
|||||||
use super::wasm_externtype_t;
|
use super::{wasm_externtype_t, WasmExternType};
|
||||||
use wasmer::{ExternType, MemoryType, Pages};
|
use wasmer::{ExternType, MemoryType, Pages};
|
||||||
|
|
||||||
// opaque type wrapping `MemoryType`
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct WasmMemoryType {
|
||||||
|
pub(crate) memory_type: MemoryType,
|
||||||
|
limits: Box<wasm_limits_t>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmMemoryType {
|
||||||
|
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
||||||
|
let limits = Box::new(wasm_limits_t {
|
||||||
|
min: memory_type.minimum.0 as _,
|
||||||
|
max: memory_type
|
||||||
|
.maximum
|
||||||
|
.map(|max| max.0 as _)
|
||||||
|
.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
memory_type,
|
||||||
|
limits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct wasm_memorytype_t {
|
pub struct wasm_memorytype_t {
|
||||||
pub(crate) extern_: wasm_externtype_t,
|
pub(crate) extern_type: wasm_externtype_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wasm_memorytype_t {
|
impl wasm_memorytype_t {
|
||||||
pub(crate) fn as_memorytype(&self) -> &MemoryType {
|
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
||||||
if let ExternType::Memory(ref mt) = self.extern_.inner {
|
Self {
|
||||||
mt
|
extern_type: wasm_externtype_t::new(ExternType::Memory(memory_type)),
|
||||||
} else {
|
|
||||||
unreachable!(
|
|
||||||
"Data corruption detected: `wasm_memorytype_t` does not contain a `MemoryType`"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
pub(crate) fn inner(&self) -> &WasmMemoryType {
|
||||||
Self {
|
match &self.extern_type.inner {
|
||||||
extern_: wasm_externtype_t {
|
WasmExternType::Memory(wasm_memory_type) => &wasm_memory_type,
|
||||||
inner: ExternType::Memory(memory_type),
|
_ => {
|
||||||
},
|
unreachable!("Data corruption: `wasm_memorytype_t` does not contain a memory type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_declare_vec!(memorytype);
|
wasm_declare_vec!(memorytype);
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct wasm_limits_t {
|
|
||||||
pub(crate) min: u32,
|
|
||||||
pub(crate) max: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {
|
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {
|
||||||
let min_pages = Pages(limits.min as _);
|
let min_pages = Pages(limits.min as _);
|
||||||
// u32::max_value() is a sentinel value for no max specified
|
|
||||||
let max_pages = if limits.max == LIMITS_MAX_SENTINEL {
|
let max_pages = if limits.max == LIMITS_MAX_SENTINEL {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -56,19 +65,19 @@ pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_memorytype_delete(_memorytype: Option<Box<wasm_memorytype_t>>) {}
|
pub unsafe extern "C" fn wasm_memorytype_delete(_memory_type: Option<Box<wasm_memorytype_t>>) {}
|
||||||
|
|
||||||
// TODO: fix memory leak
|
#[allow(non_camel_case_types)]
|
||||||
// this function leaks memory because the returned limits pointer is not owned
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[no_mangle]
|
#[repr(C)]
|
||||||
pub unsafe extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> *const wasm_limits_t {
|
pub struct wasm_limits_t {
|
||||||
let md = mt.as_memorytype();
|
pub(crate) min: u32,
|
||||||
|
pub(crate) max: u32,
|
||||||
Box::into_raw(Box::new(wasm_limits_t {
|
}
|
||||||
min: md.minimum.0 as _,
|
|
||||||
max: md
|
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||||
.maximum
|
|
||||||
.map(|max| max.0 as _)
|
#[no_mangle]
|
||||||
.unwrap_or(LIMITS_MAX_SENTINEL),
|
pub unsafe extern "C" fn wasm_memorytype_limits(memory_type: &wasm_memorytype_t) -> &wasm_limits_t {
|
||||||
}))
|
memory_type.inner().limits.as_ref()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +1,91 @@
|
|||||||
use super::{wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t};
|
use super::{
|
||||||
|
wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t, WasmExternType,
|
||||||
|
};
|
||||||
use wasmer::{ExternType, TableType};
|
use wasmer::{ExternType, TableType};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type wasm_table_size_t = u32;
|
pub type wasm_table_size_t = u32;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[repr(C)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct wasm_tabletype_t {
|
pub(crate) struct WasmTableType {
|
||||||
pub(crate) extern_: wasm_externtype_t,
|
pub(crate) table_type: TableType,
|
||||||
|
limits: Box<wasm_limits_t>,
|
||||||
|
content: Box<wasm_valtype_t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_declare_vec!(tabletype);
|
impl WasmTableType {
|
||||||
|
pub(crate) fn new(table_type: TableType) -> Self {
|
||||||
|
let limits = Box::new(wasm_limits_t {
|
||||||
|
min: table_type.minimum as _,
|
||||||
|
max: table_type.maximum.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||||
|
});
|
||||||
|
let content = Box::new(table_type.ty.into());
|
||||||
|
|
||||||
impl wasm_tabletype_t {
|
Self {
|
||||||
pub(crate) fn as_tabletype(&self) -> &TableType {
|
table_type,
|
||||||
if let ExternType::Table(ref t) = self.extern_.inner {
|
limits,
|
||||||
t
|
content,
|
||||||
} else {
|
|
||||||
unreachable!(
|
|
||||||
"Data corruption detected: `wasm_tabletype_t` does not contain a `TableType`"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct wasm_tabletype_t {
|
||||||
|
pub(crate) extern_type: wasm_externtype_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl wasm_tabletype_t {
|
||||||
|
pub(crate) fn new(table_type: TableType) -> Self {
|
||||||
|
Self {
|
||||||
|
extern_type: wasm_externtype_t::new(ExternType::Table(table_type)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn inner(&self) -> &WasmTableType {
|
||||||
|
match &self.extern_type.inner {
|
||||||
|
WasmExternType::Table(wasm_table_type) => &wasm_table_type,
|
||||||
|
_ => unreachable!("Data corruption: `wasm_tabletype_t` does not contain a table type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_declare_vec!(tabletype);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_tabletype_new(
|
pub unsafe extern "C" fn wasm_tabletype_new(
|
||||||
// own
|
valtype: Option<Box<wasm_valtype_t>>,
|
||||||
valtype: Box<wasm_valtype_t>,
|
|
||||||
limits: &wasm_limits_t,
|
limits: &wasm_limits_t,
|
||||||
) -> Box<wasm_tabletype_t> {
|
) -> Option<Box<wasm_tabletype_t>> {
|
||||||
// TODO: investigate if `0` is in fact a sentinel value here
|
let valtype = valtype?;
|
||||||
let max_elements = if limits.max == 0 {
|
let max_elements = if limits.max == LIMITS_MAX_SENTINEL {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(limits.max as _)
|
Some(limits.max as _)
|
||||||
};
|
};
|
||||||
let out = Box::new(wasm_tabletype_t {
|
let table_type = Box::new(wasm_tabletype_t::new(TableType::new(
|
||||||
extern_: wasm_externtype_t {
|
(*valtype).into(),
|
||||||
inner: ExternType::Table(TableType::new(
|
limits.min as _,
|
||||||
(*valtype).into(),
|
max_elements,
|
||||||
limits.min as _,
|
)));
|
||||||
max_elements,
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
wasm_valtype_delete(Some(valtype));
|
wasm_valtype_delete(Some(valtype));
|
||||||
|
|
||||||
out
|
Some(table_type)
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: fix memory leak
|
|
||||||
// this function leaks memory because the returned limits pointer is not owned
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_tabletype_limits(
|
|
||||||
tabletype: &wasm_tabletype_t,
|
|
||||||
) -> *const wasm_limits_t {
|
|
||||||
let tt = tabletype.as_tabletype();
|
|
||||||
Box::into_raw(Box::new(wasm_limits_t {
|
|
||||||
min: tt.minimum as _,
|
|
||||||
max: tt.maximum.unwrap_or(0),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: fix memory leak
|
|
||||||
// this function leaks memory because the returned limits pointer is not owned
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn wasm_tabletype_element(
|
|
||||||
tabletype: &wasm_tabletype_t,
|
|
||||||
) -> *const wasm_valtype_t {
|
|
||||||
let tt = tabletype.as_tabletype();
|
|
||||||
|
|
||||||
Box::into_raw(Box::new(tt.ty.into()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option<Box<wasm_tabletype_t>>) {}
|
pub unsafe extern "C" fn wasm_tabletype_limits(table_type: &wasm_tabletype_t) -> &wasm_limits_t {
|
||||||
|
table_type.inner().limits.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_tabletype_element(table_type: &wasm_tabletype_t) -> &wasm_valtype_t {
|
||||||
|
table_type.inner().content.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasm_tabletype_delete(_table_type: Option<Box<wasm_tabletype_t>>) {}
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ wasm_declare_boxed_vec!(valtype);
|
|||||||
|
|
||||||
impl From<wasm_valtype_t> for ValType {
|
impl From<wasm_valtype_t> for ValType {
|
||||||
fn from(other: wasm_valtype_t) -> Self {
|
fn from(other: wasm_valtype_t) -> Self {
|
||||||
|
(&other).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&wasm_valtype_t> for ValType {
|
||||||
|
fn from(other: &wasm_valtype_t) -> Self {
|
||||||
other.valkind.into()
|
other.valkind.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,6 +82,7 @@ impl From<ValType> for wasm_valtype_t {
|
|||||||
pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option<Box<wasm_valtype_t>> {
|
pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option<Box<wasm_valtype_t>> {
|
||||||
let kind_enum = kind.try_into().ok()?;
|
let kind_enum = kind.try_into().ok()?;
|
||||||
let valtype = wasm_valtype_t { valkind: kind_enum };
|
let valtype = wasm_valtype_t { valkind: kind_enum };
|
||||||
|
|
||||||
Some(Box::new(valtype))
|
Some(Box::new(valtype))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::types::{wasm_ref_t, wasm_valkind_enum};
|
use super::types::{wasm_ref_t, wasm_valkind_enum};
|
||||||
|
use crate::error::{update_last_error, CApiError};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::ptr::NonNull;
|
|
||||||
use wasmer::Val;
|
use wasmer::Val;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@@ -35,25 +35,43 @@ impl Clone for wasm_val_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_val_copy(out_ptr: *mut wasm_val_t, val: &wasm_val_t) {
|
pub unsafe extern "C" fn wasm_val_copy(
|
||||||
(*out_ptr).kind = val.kind;
|
// own
|
||||||
(*out_ptr).of =
|
out: &mut wasm_val_t,
|
||||||
// TODO: handle this error
|
val: &wasm_val_t,
|
||||||
match val.kind.try_into().unwrap() {
|
) {
|
||||||
wasm_valkind_enum::WASM_I32 => wasm_val_inner { int32_t: val.of.int32_t },
|
out.kind = val.kind;
|
||||||
wasm_valkind_enum::WASM_I64 => wasm_val_inner { int64_t: val.of.int64_t },
|
out.of = match val.kind.try_into() {
|
||||||
wasm_valkind_enum::WASM_F32 => wasm_val_inner { float32_t: val.of.float32_t },
|
Ok(kind) => match kind {
|
||||||
wasm_valkind_enum::WASM_F64 => wasm_val_inner { float64_t: val.of.float64_t },
|
wasm_valkind_enum::WASM_I32 => wasm_val_inner {
|
||||||
|
int32_t: val.of.int32_t,
|
||||||
|
},
|
||||||
|
wasm_valkind_enum::WASM_I64 => wasm_val_inner {
|
||||||
|
int64_t: val.of.int64_t,
|
||||||
|
},
|
||||||
|
wasm_valkind_enum::WASM_F32 => wasm_val_inner {
|
||||||
|
float32_t: val.of.float32_t,
|
||||||
|
},
|
||||||
|
wasm_valkind_enum::WASM_F64 => wasm_val_inner {
|
||||||
|
float64_t: val.of.float64_t,
|
||||||
|
},
|
||||||
wasm_valkind_enum::WASM_ANYREF => wasm_val_inner { wref: val.of.wref },
|
wasm_valkind_enum::WASM_ANYREF => wasm_val_inner { wref: val.of.wref },
|
||||||
wasm_valkind_enum::WASM_FUNCREF => wasm_val_inner { wref: val.of.wref },
|
wasm_valkind_enum::WASM_FUNCREF => wasm_val_inner { wref: val.of.wref },
|
||||||
};
|
},
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
update_last_error(CApiError { msg: e.to_string() });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_val_delete(val: Option<NonNull<wasm_val_t>>) {
|
pub unsafe extern "C" fn wasm_val_delete(val: Option<Box<wasm_val_t>>) {
|
||||||
if let Some(v_inner) = val {
|
if let Some(val) = val {
|
||||||
// TODO: figure out where wasm_val is allocated first...
|
// TODO: figure out where wasm_val is allocated first...
|
||||||
let _ = Box::from_raw(v_inner.as_ptr());
|
let _ = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ use std::str;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_module_name(module: &wasm_module_t, out: &mut wasm_name_t) {
|
pub unsafe extern "C" fn wasm_module_name(
|
||||||
|
module: &wasm_module_t,
|
||||||
|
// own
|
||||||
|
out: &mut wasm_name_t,
|
||||||
|
) {
|
||||||
let name = match module.inner.name() {
|
let name = match module.inner.name() {
|
||||||
Some(name) => name,
|
Some(name) => name,
|
||||||
None => return,
|
None => return,
|
||||||
@@ -18,7 +22,8 @@ pub unsafe extern "C" fn wasm_module_name(module: &wasm_module_t, out: &mut wasm
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasm_module_set_name(
|
pub unsafe extern "C" fn wasm_module_set_name(
|
||||||
module: &mut wasm_module_t,
|
module: &mut wasm_module_t,
|
||||||
name: &wasm_name_t,
|
// own
|
||||||
|
name: Box<wasm_name_t>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let name = match name.into_slice() {
|
let name = match name.into_slice() {
|
||||||
Some(name) => match str::from_utf8(name) {
|
Some(name) => match str::from_utf8(name) {
|
||||||
|
|||||||
@@ -12,3 +12,71 @@ pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t) -> Option<Box<wasm_byte
|
|||||||
|
|
||||||
Some(Box::new(result))
|
Some(Box::new(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use inline_c::assert_c;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wat2wasm() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(&wat, "(module)");
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
assert(wasm);
|
||||||
|
assert(wasm->size == 8);
|
||||||
|
assert(
|
||||||
|
wasm->data[0] == 0 &&
|
||||||
|
wasm->data[1] == 'a' &&
|
||||||
|
wasm->data[2] == 's' &&
|
||||||
|
wasm->data[3] == 'm' &&
|
||||||
|
wasm->data[4] == 1 &&
|
||||||
|
wasm->data[5] == 0 &&
|
||||||
|
wasm->data[6] == 0 &&
|
||||||
|
wasm->data[7] == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
wasm_byte_vec_delete(wasm);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wat2wasm_failed() {
|
||||||
|
(assert_c! {
|
||||||
|
#include "tests/wasmer_wasm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasmer_byte_vec_new_from_string(&wat, "(module");
|
||||||
|
wasm_byte_vec_t* wasm = wat2wasm(&wat);
|
||||||
|
|
||||||
|
assert(!wasm);
|
||||||
|
assert(wasmer_last_error_length() > 0);
|
||||||
|
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ project (WasmerWasmCApiTests)
|
|||||||
# Examples as tests from the `wasm-c-api` repository.
|
# Examples as tests from the `wasm-c-api` repository.
|
||||||
add_executable(wasm-c-api-callback wasm-c-api/example/callback.c)
|
add_executable(wasm-c-api-callback wasm-c-api/example/callback.c)
|
||||||
#add_executable(wasm-c-api-finalize wasm-c-api/example/finalize.c)
|
#add_executable(wasm-c-api-finalize wasm-c-api/example/finalize.c)
|
||||||
#add_executable(wasm-c-api-global wasm-c-api/example/global.c)
|
add_executable(wasm-c-api-global wasm-c-api/example/global.c)
|
||||||
add_executable(wasm-c-api-hello wasm-c-api/example/hello.c)
|
add_executable(wasm-c-api-hello wasm-c-api/example/hello.c)
|
||||||
#add_executable(wasm-c-api-hostref wasm-c-api/example/hostref.c)
|
#add_executable(wasm-c-api-hostref wasm-c-api/example/hostref.c)
|
||||||
#add_executable(wasm-c-api-memory wasm-c-api/example/memory.c)
|
add_executable(wasm-c-api-memory wasm-c-api/example/memory.c)
|
||||||
#add_executable(wasm-c-api-multi wasm-c-api/example/multi.c)
|
#add_executable(wasm-c-api-multi wasm-c-api/example/multi.c)
|
||||||
add_executable(wasm-c-api-reflect wasm-c-api/example/reflect.c)
|
add_executable(wasm-c-api-reflect wasm-c-api/example/reflect.c)
|
||||||
add_executable(wasm-c-api-serialize wasm-c-api/example/serialize.c)
|
add_executable(wasm-c-api-serialize wasm-c-api/example/serialize.c)
|
||||||
#add_executable(wasm-c-api-start wasm-c-api/example/start.c)
|
add_executable(wasm-c-api-start wasm-c-api/example/start.c)
|
||||||
#add_executable(wasm-c-api-table wasm-c-api/example/table.c)
|
#add_executable(wasm-c-api-table wasm-c-api/example/table.c)
|
||||||
#add_executable(wasm-c-api-threads wasm-c-api/example/threads.c)
|
#add_executable(wasm-c-api-threads wasm-c-api/example/threads.c)
|
||||||
add_executable(wasm-c-api-trap wasm-c-api/example/trap.c)
|
add_executable(wasm-c-api-trap wasm-c-api/example/trap.c)
|
||||||
@@ -57,12 +57,12 @@ add_test(NAME wasm-c-api-callback
|
|||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
||||||
#)
|
#)
|
||||||
|
|
||||||
#target_link_libraries(wasm-c-api-global general ${WASMER_LIB})
|
target_link_libraries(wasm-c-api-global general ${WASMER_LIB})
|
||||||
#target_compile_options(wasm-c-api-global PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(wasm-c-api-global PRIVATE ${COMPILER_OPTIONS})
|
||||||
#add_test(NAME wasm-c-api-global
|
add_test(NAME wasm-c-api-global
|
||||||
# COMMAND wasm-c-api-global
|
COMMAND wasm-c-api-global
|
||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
||||||
#)
|
)
|
||||||
|
|
||||||
target_link_libraries(wasm-c-api-hello general ${WASMER_LIB})
|
target_link_libraries(wasm-c-api-hello general ${WASMER_LIB})
|
||||||
target_compile_options(wasm-c-api-hello PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(wasm-c-api-hello PRIVATE ${COMPILER_OPTIONS})
|
||||||
@@ -78,12 +78,12 @@ add_test(NAME wasm-c-api-hello
|
|||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
||||||
#)
|
#)
|
||||||
|
|
||||||
#target_link_libraries(wasm-c-api-memory general ${WASMER_LIB})
|
target_link_libraries(wasm-c-api-memory general ${WASMER_LIB})
|
||||||
#target_compile_options(wasm-c-api-memory PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(wasm-c-api-memory PRIVATE ${COMPILER_OPTIONS})
|
||||||
#add_test(NAME wasm-c-api-memory
|
add_test(NAME wasm-c-api-memory
|
||||||
# COMMAND wasm-c-api-memory
|
COMMAND wasm-c-api-memory
|
||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
||||||
#)
|
)
|
||||||
|
|
||||||
#target_link_libraries(wasm-c-api-multi general ${WASMER_LIB})
|
#target_link_libraries(wasm-c-api-multi general ${WASMER_LIB})
|
||||||
#target_compile_options(wasm-c-api-multi PRIVATE ${COMPILER_OPTIONS})
|
#target_compile_options(wasm-c-api-multi PRIVATE ${COMPILER_OPTIONS})
|
||||||
@@ -106,12 +106,12 @@ add_test(NAME wasm-c-api-serialize
|
|||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
||||||
)
|
)
|
||||||
|
|
||||||
#target_link_libraries(wasm-c-api-start general ${WASMER_LIB})
|
target_link_libraries(wasm-c-api-start general ${WASMER_LIB})
|
||||||
#target_compile_options(wasm-c-api-start PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(wasm-c-api-start PRIVATE ${COMPILER_OPTIONS})
|
||||||
#add_test(NAME wasm-c-api-start
|
add_test(NAME wasm-c-api-start
|
||||||
# COMMAND wasm-c-api-start
|
COMMAND wasm-c-api-start
|
||||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
|
||||||
#)
|
)
|
||||||
|
|
||||||
#target_link_libraries(wasm-c-api-table general ${WASMER_LIB})
|
#target_link_libraries(wasm-c-api-table general ${WASMER_LIB})
|
||||||
#target_compile_options(wasm-c-api-table PRIVATE ${COMPILER_OPTIONS})
|
#target_compile_options(wasm-c-api-table PRIVATE ${COMPILER_OPTIONS})
|
||||||
|
|||||||
24
lib/c-api/tests/wasmer_wasm.h
Normal file
24
lib/c-api/tests/wasmer_wasm.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// This header file is used only for test purposes! It is used by unit
|
||||||
|
// test inside the `src/` directory for the moment.
|
||||||
|
|
||||||
|
#ifndef TEST_WASMER_WASM
|
||||||
|
#define TEST_WASMER_WASM
|
||||||
|
|
||||||
|
#include "../wasmer_wasm.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Assert that a `wasm_name_t` equals something.
|
||||||
|
void wasmer_assert_name(const wasm_name_t *name, const char *expected) {
|
||||||
|
assert(name->size == strlen(expected) &&
|
||||||
|
strncmp(name->data, expected, name->size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to quickly create a `wasm_byte_vec_t` from a string, à la
|
||||||
|
// `wasm_name_new_from_string`.
|
||||||
|
static inline void wasmer_byte_vec_new_from_string(wasm_byte_vec_t *out,
|
||||||
|
const char *s) {
|
||||||
|
wasm_byte_vec_new(out, strlen(s), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TEST_WASMER_WASM */
|
||||||
@@ -29,6 +29,9 @@
|
|||||||
# define DEPRECATED(message) __declspec(deprecated(message))
|
# define DEPRECATED(message) __declspec(deprecated(message))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The `jit` feature has been enabled for this build.
|
||||||
|
#define WASMER_JIT_ENABLED
|
||||||
|
|
||||||
// The `compiler` feature has been enabled for this build.
|
// The `compiler` feature has been enabled for this build.
|
||||||
#define WASMER_COMPILER_ENABLED
|
#define WASMER_COMPILER_ENABLED
|
||||||
|
|
||||||
@@ -53,7 +56,10 @@
|
|||||||
#include "wasm.h"
|
#include "wasm.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this can be a wasmer-specific type with wasmer-specific functions for manipulating it
|
* Kind of compilers that can be used by the engines.
|
||||||
|
*
|
||||||
|
* This is a Wasmer-specific type with Wasmer-specific functions for
|
||||||
|
* manipulating it.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CRANELIFT = 0,
|
CRANELIFT = 0,
|
||||||
@@ -61,6 +67,12 @@ typedef enum {
|
|||||||
SINGLEPASS = 2,
|
SINGLEPASS = 2,
|
||||||
} wasmer_compiler_t;
|
} wasmer_compiler_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kind of engines that can be used by the store.
|
||||||
|
*
|
||||||
|
* This is a Wasmer-specific type with Wasmer-specific functions for
|
||||||
|
* manipulating it.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JIT = 0,
|
JIT = 0,
|
||||||
NATIVE = 1,
|
NATIVE = 1,
|
||||||
@@ -156,13 +168,19 @@ wasm_func_t *wasi_get_start_function(wasm_instance_t *instance);
|
|||||||
wasi_version_t wasi_get_wasi_version(const wasm_module_t *module);
|
wasi_version_t wasi_get_wasi_version(const wasm_module_t *module);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the compiler to use.
|
||||||
|
*/
|
||||||
void wasm_config_set_compiler(wasm_config_t *config, wasmer_compiler_t compiler);
|
void wasm_config_set_compiler(wasm_config_t *config, wasmer_compiler_t compiler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the engine to use.
|
||||||
|
*/
|
||||||
void wasm_config_set_engine(wasm_config_t *config, wasmer_engine_t engine);
|
void wasm_config_set_engine(wasm_config_t *config, wasmer_engine_t engine);
|
||||||
|
|
||||||
void wasm_module_name(const wasm_module_t *module, wasm_name_t *out);
|
void wasm_module_name(const wasm_module_t *module, wasm_name_t *out);
|
||||||
|
|
||||||
bool wasm_module_set_name(wasm_module_t *module, const wasm_name_t *name);
|
bool wasm_module_set_name(wasm_module_t *module, wasm_name_t *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the length in bytes of the last error if any.
|
* Gets the length in bytes of the last error if any.
|
||||||
|
|||||||
4
lib/cache/Cargo.toml
vendored
4
lib/cache/Cargo.toml
vendored
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-cache"
|
name = "wasmer-cache"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Cache system for Wasmer WebAssembly runtime"
|
description = "Cache system for Wasmer WebAssembly runtime"
|
||||||
categories = ["wasm", "caching"]
|
categories = ["wasm", "caching"]
|
||||||
keywords = ["wasm", "webassembly", "cache"]
|
keywords = ["wasm", "webassembly", "cache"]
|
||||||
@@ -11,7 +11,7 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer = { path = "../api", version = "1.0.0-alpha4", default-features = false }
|
wasmer = { path = "../api", version = "1.0.0-alpha5", default-features = false }
|
||||||
memmap = "0.7"
|
memmap = "0.7"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-cli"
|
name = "wasmer-cli"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer CLI"
|
description = "Wasmer CLI"
|
||||||
categories = ["wasm", "command-line-interface"]
|
categories = ["wasm", "command-line-interface"]
|
||||||
keywords = ["wasm", "webassembly", "cli"]
|
keywords = ["wasm", "webassembly", "cli"]
|
||||||
@@ -17,22 +17,22 @@ path = "src/bin/wasmer.rs"
|
|||||||
doc = false
|
doc = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer = { version = "1.0.0-alpha4", path = "../api", default-features = false }
|
wasmer = { version = "1.0.0-alpha5", path = "../api", default-features = false }
|
||||||
wasmer-compiler = { version = "1.0.0-alpha4", path = "../compiler" }
|
wasmer-compiler = { version = "1.0.0-alpha5", path = "../compiler" }
|
||||||
wasmer-compiler-cranelift = { version = "1.0.0-alpha4", path = "../compiler-cranelift", optional = true }
|
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "../compiler-cranelift", optional = true }
|
||||||
wasmer-compiler-singlepass = { version = "1.0.0-alpha4", path = "../compiler-singlepass", optional = true }
|
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "../compiler-singlepass", optional = true }
|
||||||
wasmer-compiler-llvm = { version = "1.0.0-alpha4", path = "../compiler-llvm", optional = true }
|
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "../compiler-llvm", optional = true }
|
||||||
wasmer-emscripten = { version = "1.0.0-alpha4", path = "../emscripten", optional = true }
|
wasmer-emscripten = { version = "1.0.0-alpha5", path = "../emscripten", optional = true }
|
||||||
wasmer-engine = { version = "1.0.0-alpha4", path = "../engine" }
|
wasmer-engine = { version = "1.0.0-alpha5", path = "../engine" }
|
||||||
wasmer-engine-jit = { version = "1.0.0-alpha4", path = "../engine-jit", optional = true }
|
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "../engine-jit", optional = true }
|
||||||
wasmer-engine-native = { version = "1.0.0-alpha4", path = "../engine-native", optional = true }
|
wasmer-engine-native = { version = "1.0.0-alpha5", path = "../engine-native", optional = true }
|
||||||
wasmer-engine-object-file = { version = "1.0.0-alpha4", path = "../engine-object-file", optional = true }
|
wasmer-engine-object-file = { version = "1.0.0-alpha5", path = "../engine-object-file", optional = true }
|
||||||
wasmer-vm = { version = "1.0.0-alpha4", path = "../vm" }
|
wasmer-vm = { version = "1.0.0-alpha5", path = "../vm" }
|
||||||
wasmer-wasi = { version = "1.0.0-alpha4", path = "../wasi", optional = true }
|
wasmer-wasi = { version = "1.0.0-alpha5", path = "../wasi", optional = true }
|
||||||
wasmer-wasi-experimental-io-devices = { version = "1.0.0-alpha4", path = "../wasi-experimental-io-devices", optional = true }
|
wasmer-wasi-experimental-io-devices = { version = "1.0.0-alpha5", path = "../wasi-experimental-io-devices", optional = true }
|
||||||
wasmer-wast = { version = "1.0.0-alpha4", path = "../../tests/lib/wast", optional = true }
|
wasmer-wast = { version = "1.0.0-alpha5", path = "../../tests/lib/wast", optional = true }
|
||||||
wasmer-cache = { version = "1.0.0-alpha4", path = "../cache", optional = true }
|
wasmer-cache = { version = "1.0.0-alpha5", path = "../cache", optional = true }
|
||||||
wasmer-types = { version = "1.0.0-alpha4", path = "../wasmer-types" }
|
wasmer-types = { version = "1.0.0-alpha5", path = "../wasmer-types" }
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
colored = "2.0"
|
colored = "2.0"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
@@ -41,7 +41,7 @@ structopt = { version = "0.3", features = ["suggestions"] }
|
|||||||
distance = "0.4"
|
distance = "0.4"
|
||||||
# For the inspect subcommand
|
# For the inspect subcommand
|
||||||
bytesize = "1.0"
|
bytesize = "1.0"
|
||||||
cfg-if = "0.1"
|
cfg-if = "1.0"
|
||||||
# For debug feature
|
# For debug feature
|
||||||
fern = { version = "0.6", features = ["colored"], optional = true }
|
fern = { version = "0.6", features = ["colored"], optional = true }
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-compiler-cranelift"
|
name = "wasmer-compiler-cranelift"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Cranelift compiler for Wasmer WebAssembly runtime"
|
description = "Cranelift compiler for Wasmer WebAssembly runtime"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "compiler", "cranelift"]
|
keywords = ["wasm", "webassembly", "compiler", "cranelift"]
|
||||||
@@ -12,21 +12,22 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"], default-features = false }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"], default-features = false }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4", default-features = false, features = ["std"] }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5", default-features = false, features = ["std"] }
|
||||||
cranelift-codegen = { version = "0.65", default-features = false, features = ["x86", "arm64"] }
|
cranelift-codegen = { version = "0.67", default-features = false, features = ["x86", "arm64"] }
|
||||||
cranelift-frontend = { version = "0.65", default-features = false }
|
cranelift-frontend = { version = "0.67", default-features = false }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
hashbrown = { version = "0.8", optional = true }
|
hashbrown = { version = "0.9", optional = true }
|
||||||
rayon = "1.3"
|
rayon = "1.5"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
more-asserts = "0.2"
|
more-asserts = "0.2"
|
||||||
gimli = { version = "0.21", optional = true }
|
gimli = { version = "0.21", optional = true }
|
||||||
|
smallvec = "1.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
target-lexicon = { version = "0.10", default-features = false }
|
target-lexicon = { version = "0.11", default-features = false }
|
||||||
cranelift-codegen = { version = "0.65", features = ["enable-serde", "all-arch"] }
|
cranelift-codegen = { version = "0.67", features = ["enable-serde", "all-arch"] }
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
@@ -35,6 +36,6 @@ maintenance = { status = "actively-developed" }
|
|||||||
[features]
|
[features]
|
||||||
default = ["std", "enable-serde", "unwind"]
|
default = ["std", "enable-serde", "unwind"]
|
||||||
unwind = ["cranelift-codegen/unwind", "gimli"]
|
unwind = ["cranelift-codegen/unwind", "gimli"]
|
||||||
enable-serde = ["wasmer-compiler/enable-serde", "cranelift-codegen/enable-serde", "wasmer-types/enable-serde"]
|
enable-serde = ["wasmer-compiler/enable-serde", "wasmer-types/enable-serde"]
|
||||||
std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmer-compiler/std", "wasmer-types/std"]
|
std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmer-compiler/std", "wasmer-types/std"]
|
||||||
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]
|
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ impl Compiler for CraneliftCompiler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let functions = function_body_inputs
|
let functions = function_body_inputs
|
||||||
.into_iter()
|
.iter()
|
||||||
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map_init(FuncTranslator::new, |func_translator, (i, input)| {
|
.map_init(FuncTranslator::new, |func_translator, (i, input)| {
|
||||||
@@ -127,7 +127,7 @@ impl Compiler for CraneliftCompiler {
|
|||||||
let mut code_buf: Vec<u8> = Vec::new();
|
let mut code_buf: Vec<u8> = Vec::new();
|
||||||
let mut reloc_sink = RelocSink::new(module, func_index);
|
let mut reloc_sink = RelocSink::new(module, func_index);
|
||||||
let mut trap_sink = TrapSink::new();
|
let mut trap_sink = TrapSink::new();
|
||||||
let mut stackmap_sink = binemit::NullStackmapSink {};
|
let mut stackmap_sink = binemit::NullStackMapSink {};
|
||||||
context
|
context
|
||||||
.compile_and_emit(
|
.compile_and_emit(
|
||||||
&*isa,
|
&*isa,
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ 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 std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
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;
|
||||||
@@ -538,10 +540,11 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
fn translate_table_grow(
|
fn translate_table_grow(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: TableIndex,
|
_table_index: TableIndex,
|
||||||
_: ir::Value,
|
_table: ir::Table,
|
||||||
_: ir::Value,
|
_delta: ir::Value,
|
||||||
|
_init_value: ir::Value,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
"the `table.grow` instruction is not supported yet".into(),
|
"the `table.grow` instruction is not supported yet".into(),
|
||||||
@@ -550,9 +553,10 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
fn translate_table_get(
|
fn translate_table_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
_builder: &mut FunctionBuilder,
|
||||||
_: TableIndex,
|
_table_index: TableIndex,
|
||||||
_: ir::Value,
|
_table: ir::Table,
|
||||||
|
_index: ir::Value,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
"the `table.get` instruction is not supported yet".into(),
|
"the `table.get` instruction is not supported yet".into(),
|
||||||
@@ -561,10 +565,11 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
fn translate_table_set(
|
fn translate_table_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
_builder: &mut FunctionBuilder,
|
||||||
_: TableIndex,
|
_table_index: TableIndex,
|
||||||
_: ir::Value,
|
_table: ir::Table,
|
||||||
_: ir::Value,
|
_value: ir::Value,
|
||||||
|
_index: ir::Value,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
"the `table.set` instruction is not supported yet".into(),
|
"the `table.set` instruction is not supported yet".into(),
|
||||||
@@ -573,21 +578,56 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
fn translate_table_fill(
|
fn translate_table_fill(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: TableIndex,
|
_table_index: TableIndex,
|
||||||
_: ir::Value,
|
_dst: ir::Value,
|
||||||
_: ir::Value,
|
_val: ir::Value,
|
||||||
_: ir::Value,
|
_len: ir::Value,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
"the `table.fill` instruction is not supported yet".into(),
|
"the `table.fill` instruction is not supported yet".into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn translate_ref_null(
|
||||||
|
&mut self,
|
||||||
|
mut pos: cranelift_codegen::cursor::FuncCursor,
|
||||||
|
ty: Type,
|
||||||
|
) -> WasmResult<ir::Value> {
|
||||||
|
Ok(match ty {
|
||||||
|
Type::FuncRef => pos.ins().iconst(self.pointer_type(), 0),
|
||||||
|
// Type::ExternRef => pos.ins().null(self.reference_type(ty)),
|
||||||
|
_ => {
|
||||||
|
return Err(WasmError::Unsupported(
|
||||||
|
"`ref.null T` that is not a `funcref`".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn translate_ref_is_null(
|
||||||
|
&mut self,
|
||||||
|
mut pos: cranelift_codegen::cursor::FuncCursor,
|
||||||
|
value: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value> {
|
||||||
|
let bool_is_null = match pos.func.dfg.value_type(value) {
|
||||||
|
// `externref`
|
||||||
|
ty if ty.is_ref() => pos.ins().is_null(value),
|
||||||
|
// `funcref`
|
||||||
|
ty if ty == self.pointer_type() => {
|
||||||
|
pos.ins()
|
||||||
|
.icmp_imm(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(pos.ins().bint(ir::types::I32, bool_is_null))
|
||||||
|
}
|
||||||
|
|
||||||
fn translate_ref_func(
|
fn translate_ref_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: u32,
|
_func_index: FunctionIndex,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
"the `ref.func` instruction is not supported yet".into(),
|
"the `ref.func` instruction is not supported yet".into(),
|
||||||
@@ -596,17 +636,17 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
fn translate_custom_global_get(
|
fn translate_custom_global_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: GlobalIndex,
|
_index: GlobalIndex,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
unreachable!("we don't make any custom globals")
|
unreachable!("we don't make any custom globals")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_custom_global_set(
|
fn translate_custom_global_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: GlobalIndex,
|
_index: GlobalIndex,
|
||||||
_: ir::Value,
|
_value: ir::Value,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
unreachable!("we don't make any custom globals")
|
unreachable!("we don't make any custom globals")
|
||||||
}
|
}
|
||||||
@@ -771,7 +811,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
match self.table_styles[table_index] {
|
match self.table_styles[table_index] {
|
||||||
TableStyle::CallerChecksSignature => {
|
TableStyle::CallerChecksSignature => {
|
||||||
let sig_id_size = self.offsets.size_of_vmshared_signature_index();
|
let sig_id_size = self.offsets.size_of_vmshared_signature_index();
|
||||||
let sig_id_type = Type::int(u16::from(sig_id_size) * 8).unwrap();
|
let sig_id_type = ir::Type::int(u16::from(sig_id_size) * 8).unwrap();
|
||||||
let vmctx = self.vmctx(pos.func);
|
let vmctx = self.vmctx(pos.func);
|
||||||
let base = pos.ins().global_value(pointer_type, vmctx);
|
let base = pos.ins().global_value(pointer_type, vmctx);
|
||||||
let offset =
|
let offset =
|
||||||
@@ -897,24 +937,22 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
fn translate_memory_copy(
|
fn translate_memory_copy(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut pos: FuncCursor,
|
mut pos: FuncCursor,
|
||||||
memory_index: MemoryIndex,
|
src_index: MemoryIndex,
|
||||||
_heap: ir::Heap,
|
_src_heap: ir::Heap,
|
||||||
|
_dst_index: MemoryIndex,
|
||||||
|
_dst_heap: ir::Heap,
|
||||||
dst: ir::Value,
|
dst: ir::Value,
|
||||||
src: ir::Value,
|
src: ir::Value,
|
||||||
len: ir::Value,
|
len: ir::Value,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let (func_sig, memory_index, func_idx) =
|
let (func_sig, src_index, func_idx) = self.get_memory_copy_func(&mut pos.func, src_index);
|
||||||
self.get_memory_copy_func(&mut pos.func, memory_index);
|
|
||||||
|
|
||||||
let memory_index_arg = pos.ins().iconst(I32, memory_index as i64);
|
let src_index_arg = pos.ins().iconst(I32, src_index as i64);
|
||||||
|
|
||||||
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
|
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
|
||||||
|
|
||||||
pos.ins().call_indirect(
|
pos.ins()
|
||||||
func_sig,
|
.call_indirect(func_sig, func_addr, &[vmctx, src_index_arg, dst, src, len]);
|
||||||
func_addr,
|
|
||||||
&[vmctx, memory_index_arg, dst, src, len],
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -981,8 +1019,8 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
fn translate_table_size(
|
fn translate_table_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
_pos: FuncCursor,
|
mut _pos: FuncCursor,
|
||||||
_index: TableIndex,
|
_table_index: TableIndex,
|
||||||
_table: ir::Table,
|
_table: ir::Table,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
@@ -1064,4 +1102,31 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn translate_atomic_wait(
|
||||||
|
&mut self,
|
||||||
|
_pos: FuncCursor,
|
||||||
|
_index: MemoryIndex,
|
||||||
|
_heap: ir::Heap,
|
||||||
|
_addr: ir::Value,
|
||||||
|
_expected: ir::Value,
|
||||||
|
_timeout: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value> {
|
||||||
|
Err(WasmError::Unsupported(
|
||||||
|
"wasm atomics (fn translate_atomic_wait)".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn translate_atomic_notify(
|
||||||
|
&mut self,
|
||||||
|
_pos: FuncCursor,
|
||||||
|
_index: MemoryIndex,
|
||||||
|
_heap: ir::Heap,
|
||||||
|
_addr: ir::Value,
|
||||||
|
_count: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value> {
|
||||||
|
Err(WasmError::Unsupported(
|
||||||
|
"wasm atomics (fn translate_atomic_notify)".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind};
|
use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind};
|
||||||
use cranelift_codegen::binemit;
|
use cranelift_codegen::binemit;
|
||||||
use cranelift_codegen::ir::{self, ExternalName};
|
use cranelift_codegen::ir::{self, ExternalName};
|
||||||
use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, SourceLoc, TrapInformation};
|
use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation};
|
||||||
use wasmer_types::entity::EntityRef;
|
use wasmer_types::entity::EntityRef;
|
||||||
use wasmer_types::{FunctionIndex, LocalFunctionIndex};
|
use wasmer_types::{FunctionIndex, LocalFunctionIndex};
|
||||||
use wasmer_vm::{ModuleInfo, TrapCode};
|
use wasmer_vm::{ModuleInfo, TrapCode};
|
||||||
@@ -108,12 +108,11 @@ impl binemit::TrapSink for TrapSink {
|
|||||||
fn trap(
|
fn trap(
|
||||||
&mut self,
|
&mut self,
|
||||||
code_offset: binemit::CodeOffset,
|
code_offset: binemit::CodeOffset,
|
||||||
source_loc: ir::SourceLoc,
|
_source_loc: ir::SourceLoc,
|
||||||
trap_code: ir::TrapCode,
|
trap_code: ir::TrapCode,
|
||||||
) {
|
) {
|
||||||
self.traps.push(TrapInformation {
|
self.traps.push(TrapInformation {
|
||||||
code_offset,
|
code_offset,
|
||||||
source_loc: SourceLoc::new(source_loc.bits()),
|
|
||||||
// TODO: Translate properly environment Trapcode into cranelift IR
|
// TODO: Translate properly environment Trapcode into cranelift IR
|
||||||
trap_code: translate_ir_trapcode(trap_code),
|
trap_code: translate_ir_trapcode(trap_code),
|
||||||
});
|
});
|
||||||
@@ -125,6 +124,7 @@ fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
|
|||||||
match trap {
|
match trap {
|
||||||
ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
|
ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
|
||||||
ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds,
|
ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds,
|
||||||
|
ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned,
|
||||||
ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds,
|
ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds,
|
||||||
ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
|
ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
|
||||||
ir::TrapCode::BadSignature => TrapCode::BadSignature,
|
ir::TrapCode::BadSignature => TrapCode::BadSignature,
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ pub fn make_trampoline_dynamic_function(
|
|||||||
let mut code_buf = Vec::new();
|
let mut code_buf = Vec::new();
|
||||||
let mut reloc_sink = TrampolineRelocSink {};
|
let mut reloc_sink = TrampolineRelocSink {};
|
||||||
let mut trap_sink = binemit::NullTrapSink {};
|
let mut trap_sink = binemit::NullTrapSink {};
|
||||||
let mut stackmap_sink = binemit::NullStackmapSink {};
|
let mut stackmap_sink = binemit::NullStackMapSink {};
|
||||||
context
|
context
|
||||||
.compile_and_emit(
|
.compile_and_emit(
|
||||||
isa,
|
isa,
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ pub fn make_trampoline_function_call(
|
|||||||
let mut code_buf = Vec::new();
|
let mut code_buf = Vec::new();
|
||||||
let mut reloc_sink = TrampolineRelocSink {};
|
let mut reloc_sink = TrampolineRelocSink {};
|
||||||
let mut trap_sink = binemit::NullTrapSink {};
|
let mut trap_sink = binemit::NullTrapSink {};
|
||||||
let mut stackmap_sink = binemit::NullStackmapSink {};
|
let mut stackmap_sink = binemit::NullStackMapSink {};
|
||||||
|
|
||||||
context
|
context
|
||||||
.compile_and_emit(
|
.compile_and_emit(
|
||||||
|
|||||||
@@ -6,19 +6,13 @@ mod function_call;
|
|||||||
pub use self::dynamic_function::make_trampoline_dynamic_function;
|
pub use self::dynamic_function::make_trampoline_dynamic_function;
|
||||||
pub use self::function_call::make_trampoline_function_call;
|
pub use self::function_call::make_trampoline_function_call;
|
||||||
|
|
||||||
// TODO: Delete
|
|
||||||
pub mod ir {
|
|
||||||
pub use cranelift_codegen::ir::{
|
|
||||||
ExternalName, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub use cranelift_codegen::print_errors::pretty_error;
|
pub use cranelift_codegen::print_errors::pretty_error;
|
||||||
pub use cranelift_codegen::Context;
|
pub use cranelift_codegen::Context;
|
||||||
pub use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
pub use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
|
|
||||||
pub mod binemit {
|
pub mod binemit {
|
||||||
pub use cranelift_codegen::binemit::NullTrapSink;
|
pub use cranelift_codegen::binemit::NullTrapSink;
|
||||||
pub use cranelift_codegen::binemit::{CodeOffset, NullStackmapSink, TrapSink};
|
pub use cranelift_codegen::binemit::{CodeOffset, NullStackMapSink, TrapSink};
|
||||||
|
|
||||||
use cranelift_codegen::{binemit, ir};
|
use cranelift_codegen::{binemit, ir};
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ use cranelift_codegen::ir::immediates::Offset32;
|
|||||||
use cranelift_codegen::ir::{self, InstBuilder};
|
use cranelift_codegen::ir::{self, InstBuilder};
|
||||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||||
use cranelift_frontend::FunctionBuilder;
|
use cranelift_frontend::FunctionBuilder;
|
||||||
use wasmer_compiler::wasmparser::Operator;
|
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, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex};
|
||||||
|
|
||||||
@@ -229,8 +229,10 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
fn translate_memory_copy(
|
fn translate_memory_copy(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
index: MemoryIndex,
|
src_index: MemoryIndex,
|
||||||
heap: ir::Heap,
|
src_heap: ir::Heap,
|
||||||
|
dst_index: MemoryIndex,
|
||||||
|
dst_heap: ir::Heap,
|
||||||
dst: ir::Value,
|
dst: ir::Value,
|
||||||
src: ir::Value,
|
src: ir::Value,
|
||||||
len: ir::Value,
|
len: ir::Value,
|
||||||
@@ -283,6 +285,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
table_index: TableIndex,
|
table_index: TableIndex,
|
||||||
|
table: ir::Table,
|
||||||
delta: ir::Value,
|
delta: ir::Value,
|
||||||
init_value: ir::Value,
|
init_value: ir::Value,
|
||||||
) -> WasmResult<ir::Value>;
|
) -> WasmResult<ir::Value>;
|
||||||
@@ -290,16 +293,18 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
/// Translate a `table.get` WebAssembly instruction.
|
/// Translate a `table.get` WebAssembly instruction.
|
||||||
fn translate_table_get(
|
fn translate_table_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
builder: &mut FunctionBuilder,
|
||||||
table_index: TableIndex,
|
table_index: TableIndex,
|
||||||
|
table: ir::Table,
|
||||||
index: ir::Value,
|
index: ir::Value,
|
||||||
) -> WasmResult<ir::Value>;
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
/// Translate a `table.set` WebAssembly instruction.
|
/// Translate a `table.set` WebAssembly instruction.
|
||||||
fn translate_table_set(
|
fn translate_table_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
builder: &mut FunctionBuilder,
|
||||||
table_index: TableIndex,
|
table_index: TableIndex,
|
||||||
|
table: ir::Table,
|
||||||
value: ir::Value,
|
value: ir::Value,
|
||||||
index: ir::Value,
|
index: ir::Value,
|
||||||
) -> WasmResult<()>;
|
) -> WasmResult<()>;
|
||||||
@@ -344,8 +349,44 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
/// Translate a `elem.drop` WebAssembly instruction.
|
/// Translate a `elem.drop` WebAssembly instruction.
|
||||||
fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
|
fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
|
||||||
|
|
||||||
|
/// Translate a `ref.null T` WebAssembly instruction.
|
||||||
|
///
|
||||||
|
/// By default, translates into a null reference type.
|
||||||
|
///
|
||||||
|
/// Override this if you don't use Cranelift reference types for all Wasm
|
||||||
|
/// reference types (e.g. you use a raw pointer for `funcref`s) or if the
|
||||||
|
/// null sentinel is not a null reference type pointer for your type. If you
|
||||||
|
/// override this method, then you should also override
|
||||||
|
/// `translate_ref_is_null` as well.
|
||||||
|
fn translate_ref_null(&mut self, pos: FuncCursor, ty: Type) -> WasmResult<ir::Value>;
|
||||||
|
// {
|
||||||
|
// let _ = ty;
|
||||||
|
// Ok(pos.ins().null(self.reference_type(ty)))
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Translate a `ref.is_null` WebAssembly instruction.
|
||||||
|
///
|
||||||
|
/// By default, assumes that `value` is a Cranelift reference type, and that
|
||||||
|
/// a null Cranelift reference type is the null value for all Wasm reference
|
||||||
|
/// types.
|
||||||
|
///
|
||||||
|
/// If you override this method, you probably also want to override
|
||||||
|
/// `translate_ref_null` as well.
|
||||||
|
fn translate_ref_is_null(
|
||||||
|
&mut self,
|
||||||
|
mut pos: FuncCursor,
|
||||||
|
value: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value> {
|
||||||
|
let is_null = pos.ins().is_null(value);
|
||||||
|
Ok(pos.ins().bint(ir::types::I32, is_null))
|
||||||
|
}
|
||||||
|
|
||||||
/// Translate a `ref.func` WebAssembly instruction.
|
/// Translate a `ref.func` WebAssembly instruction.
|
||||||
fn translate_ref_func(&mut self, pos: FuncCursor, func_index: u32) -> WasmResult<ir::Value>;
|
fn translate_ref_func(
|
||||||
|
&mut self,
|
||||||
|
pos: FuncCursor,
|
||||||
|
func_index: FunctionIndex,
|
||||||
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
/// Translate a `global.get` WebAssembly instruction at `pos` for a global
|
/// Translate a `global.get` WebAssembly instruction at `pos` for a global
|
||||||
/// that is custom.
|
/// that is custom.
|
||||||
@@ -364,6 +405,38 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
val: ir::Value,
|
val: ir::Value,
|
||||||
) -> WasmResult<()>;
|
) -> WasmResult<()>;
|
||||||
|
|
||||||
|
/// Translate an `i32.atomic.wait` or `i64.atomic.wait` WebAssembly instruction.
|
||||||
|
/// The `index` provided identifies the linear memory containing the value
|
||||||
|
/// to wait on, and `heap` is the heap reference returned by `make_heap`
|
||||||
|
/// for the same index. Whether the waited-on value is 32- or 64-bit can be
|
||||||
|
/// determined by examining the type of `expected`, which must be only I32 or I64.
|
||||||
|
///
|
||||||
|
/// Returns an i32, which is negative if the helper call failed.
|
||||||
|
fn translate_atomic_wait(
|
||||||
|
&mut self,
|
||||||
|
pos: FuncCursor,
|
||||||
|
index: MemoryIndex,
|
||||||
|
heap: ir::Heap,
|
||||||
|
addr: ir::Value,
|
||||||
|
expected: ir::Value,
|
||||||
|
timeout: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
|
/// Translate an `atomic.notify` WebAssembly instruction.
|
||||||
|
/// The `index` provided identifies the linear memory containing the value
|
||||||
|
/// to wait on, and `heap` is the heap reference returned by `make_heap`
|
||||||
|
/// for the same index.
|
||||||
|
///
|
||||||
|
/// Returns an i64, which is negative if the helper call failed.
|
||||||
|
fn translate_atomic_notify(
|
||||||
|
&mut self,
|
||||||
|
pos: FuncCursor,
|
||||||
|
index: MemoryIndex,
|
||||||
|
heap: ir::Heap,
|
||||||
|
addr: ir::Value,
|
||||||
|
count: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
/// Emit code at the beginning of every wasm loop.
|
/// Emit code at the beginning of every wasm loop.
|
||||||
///
|
///
|
||||||
/// This can be used to insert explicit interrupt or safepoint checking at
|
/// This can be used to insert explicit interrupt or safepoint checking at
|
||||||
|
|||||||
@@ -132,7 +132,9 @@ impl ControlStackFrame {
|
|||||||
Self::Loop { header, .. } => header,
|
Self::Loop { header, .. } => header,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn original_stack_size(&self) -> usize {
|
/// Private helper. Use `truncate_value_stack_to_else_params()` or
|
||||||
|
/// `truncate_value_stack_to_original_size()` to restore value-stack state.
|
||||||
|
fn original_stack_size(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
Self::If {
|
Self::If {
|
||||||
original_stack_size,
|
original_stack_size,
|
||||||
@@ -182,6 +184,33 @@ impl ControlStackFrame {
|
|||||||
Self::Loop { .. } => {}
|
Self::Loop { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pop values from the value stack so that it is left at the
|
||||||
|
/// input-parameters to an else-block.
|
||||||
|
pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec<Value>) {
|
||||||
|
debug_assert!(matches!(self, &ControlStackFrame::If { .. }));
|
||||||
|
stack.truncate(self.original_stack_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop values from the value stack so that it is left at the state it was
|
||||||
|
/// before this control-flow frame.
|
||||||
|
pub fn truncate_value_stack_to_original_size(&self, stack: &mut Vec<Value>) {
|
||||||
|
// The "If" frame pushes its parameters twice, so they're available to the else block
|
||||||
|
// (see also `FuncTranslationState::push_if`).
|
||||||
|
// Yet, the original_stack_size member accounts for them only once, so that the else
|
||||||
|
// block can see the same number of parameters as the consequent block. As a matter of
|
||||||
|
// fact, we need to substract an extra number of parameter values for if blocks.
|
||||||
|
let num_duplicated_params = match self {
|
||||||
|
&ControlStackFrame::If {
|
||||||
|
num_param_values, ..
|
||||||
|
} => {
|
||||||
|
debug_assert!(num_param_values <= self.original_stack_size());
|
||||||
|
num_param_values
|
||||||
|
}
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
stack.truncate(self.original_stack_size() - num_duplicated_params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains information passed along during a function's translation and that records:
|
/// Contains information passed along during a function's translation and that records:
|
||||||
@@ -219,6 +248,16 @@ pub struct FuncTranslationState {
|
|||||||
functions: HashMap<FunctionIndex, (ir::FuncRef, usize)>,
|
functions: HashMap<FunctionIndex, (ir::FuncRef, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Public methods that are exposed to non-`cranelift_wasm` API consumers.
|
||||||
|
impl FuncTranslationState {
|
||||||
|
/// True if the current translation state expresses reachable code, false if it is unreachable.
|
||||||
|
#[inline]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn reachable(&self) -> bool {
|
||||||
|
self.reachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FuncTranslationState {
|
impl FuncTranslationState {
|
||||||
/// Construct a new, empty, `FuncTranslationState`
|
/// Construct a new, empty, `FuncTranslationState`
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
@@ -441,7 +480,7 @@ impl FuncTranslationState {
|
|||||||
|
|
||||||
/// Get the `Table` reference that should be used to access table `index`.
|
/// Get the `Table` reference that should be used to access table `index`.
|
||||||
/// Create the reference if necessary.
|
/// Create the reference if necessary.
|
||||||
pub(crate) fn get_table<FE: FuncEnvironment + ?Sized>(
|
pub(crate) fn get_or_create_table<FE: FuncEnvironment + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
index: u32,
|
index: u32,
|
||||||
|
|||||||
@@ -176,12 +176,9 @@ fn parse_local_decls<FE: FuncEnvironment + ?Sized>(
|
|||||||
let mut next_local = num_params;
|
let mut next_local = num_params;
|
||||||
let local_count = reader.read_local_count().map_err(to_wasm_error)?;
|
let local_count = reader.read_local_count().map_err(to_wasm_error)?;
|
||||||
|
|
||||||
let mut locals_total = 0;
|
|
||||||
for _ in 0..local_count {
|
for _ in 0..local_count {
|
||||||
builder.set_srcloc(cur_srcloc(reader));
|
builder.set_srcloc(cur_srcloc(reader));
|
||||||
let (count, ty) = reader
|
let (count, ty) = reader.read_local_decl().map_err(to_wasm_error)?;
|
||||||
.read_local_decl(&mut locals_total)
|
|
||||||
.map_err(to_wasm_error)?;
|
|
||||||
declare_locals(builder, count, ty, &mut next_local, environ)?;
|
declare_locals(builder, count, ty, &mut next_local, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-compiler-llvm"
|
name = "wasmer-compiler-llvm"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "LLVM compiler for Wasmer WebAssembly runtime"
|
description = "LLVM compiler for Wasmer WebAssembly runtime"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "compiler", "llvm"]
|
keywords = ["wasm", "webassembly", "compiler", "llvm"]
|
||||||
@@ -12,16 +12,16 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"] }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"] }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
target-lexicon = { version = "0.10", default-features = false }
|
target-lexicon = { version = "0.11", default-features = false }
|
||||||
smallvec = "1"
|
smallvec = "1"
|
||||||
goblin = "0.2"
|
goblin = "0.2"
|
||||||
libc = { version = "^0.2.69", default-features = false }
|
libc = { version = "^0.2", default-features = false }
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
itertools = "0.9"
|
itertools = "0.9"
|
||||||
rayon = "1.3"
|
rayon = "1.5"
|
||||||
|
|
||||||
[dependencies.inkwell]
|
[dependencies.inkwell]
|
||||||
version = "=0.1.0-llvm10sample"
|
version = "=0.1.0-llvm10sample"
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ impl LLVMCompiler {
|
|||||||
compile_info
|
compile_info
|
||||||
.module
|
.module
|
||||||
.signatures
|
.signatures
|
||||||
.into_iter()
|
.iter()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map_init(
|
.map_init(
|
||||||
@@ -149,7 +149,7 @@ impl LLVMCompiler {
|
|||||||
compile_info
|
compile_info
|
||||||
.module
|
.module
|
||||||
.functions
|
.functions
|
||||||
.into_iter()
|
.iter()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map_init(
|
.map_init(
|
||||||
@@ -248,7 +248,7 @@ impl Compiler for LLVMCompiler {
|
|||||||
let mut frame_section_bytes = vec![];
|
let mut frame_section_bytes = vec![];
|
||||||
let mut frame_section_relocations = vec![];
|
let mut frame_section_relocations = vec![];
|
||||||
let functions = function_body_inputs
|
let functions = function_body_inputs
|
||||||
.into_iter()
|
.iter()
|
||||||
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map_init(
|
.map_init(
|
||||||
|
|||||||
@@ -184,10 +184,7 @@ impl FuncTranslator {
|
|||||||
let mut locals = vec![];
|
let mut locals = vec![];
|
||||||
let num_locals = reader.read_local_count().map_err(to_wasm_error)?;
|
let num_locals = reader.read_local_count().map_err(to_wasm_error)?;
|
||||||
for _ in 0..num_locals {
|
for _ in 0..num_locals {
|
||||||
let mut counter = 0;
|
let (count, ty) = reader.read_local_decl().map_err(to_wasm_error)?;
|
||||||
let (count, ty) = reader
|
|
||||||
.read_local_decl(&mut counter)
|
|
||||||
.map_err(to_wasm_error)?;
|
|
||||||
let ty = wptype_to_type(ty).map_err(to_compile_error)?;
|
let ty = wptype_to_type(ty).map_err(to_compile_error)?;
|
||||||
let ty = type_to_llvm(&intrinsics, ty)?;
|
let ty = type_to_llvm(&intrinsics, ty)?;
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
@@ -1110,21 +1107,13 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn trap_if_misaligned(&self, memarg: &MemoryImmediate, ptr: PointerValue<'ctx>) {
|
fn trap_if_misaligned(&self, memarg: &MemoryImmediate, ptr: PointerValue<'ctx>) {
|
||||||
let align = match memarg.flags & 3 {
|
let align = memarg.align;
|
||||||
0 => {
|
|
||||||
return; /* No alignment to check. */
|
|
||||||
}
|
|
||||||
1 => 2,
|
|
||||||
2 => 4,
|
|
||||||
3 => 8,
|
|
||||||
_ => unreachable!("this match is fully covered"),
|
|
||||||
};
|
|
||||||
let value = self
|
let value = self
|
||||||
.builder
|
.builder
|
||||||
.build_ptr_to_int(ptr, self.intrinsics.i64_ty, "");
|
.build_ptr_to_int(ptr, self.intrinsics.i64_ty, "");
|
||||||
let and = self.builder.build_and(
|
let and = self.builder.build_and(
|
||||||
value,
|
value,
|
||||||
self.intrinsics.i64_ty.const_int(align - 1, false),
|
self.intrinsics.i64_ty.const_int((align - 1).into(), false),
|
||||||
"misaligncheck",
|
"misaligncheck",
|
||||||
);
|
);
|
||||||
let aligned =
|
let aligned =
|
||||||
@@ -1541,7 +1530,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
.get_insert_block()
|
.get_insert_block()
|
||||||
.ok_or_else(|| CompileError::Codegen("not currently in a block".to_string()))?;
|
.ok_or_else(|| CompileError::Codegen("not currently in a block".to_string()))?;
|
||||||
|
|
||||||
let (label_depths, default_depth) = table.read_table().map_err(to_wasm_error)?;
|
let mut label_depths = table
|
||||||
|
.targets()
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map_err(to_wasm_error)?;
|
||||||
|
let default_depth = label_depths.pop().unwrap().0;
|
||||||
|
|
||||||
let index = self.state.pop1()?;
|
let index = self.state.pop1()?;
|
||||||
|
|
||||||
@@ -1561,7 +1554,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let cases: Vec<_> = label_depths
|
let cases: Vec<_> = label_depths
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(case_index, &depth)| {
|
.map(|(case_index, &(depth, _))| {
|
||||||
let frame_result: Result<&ControlFrame, CompileError> =
|
let frame_result: Result<&ControlFrame, CompileError> =
|
||||||
self.state.frame_at_depth(depth);
|
self.state.frame_at_depth(depth);
|
||||||
let frame = match frame_result {
|
let frame = match frame_result {
|
||||||
@@ -2495,7 +2488,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I8x16AddSaturateS => {
|
Operator::I8x16AddSatS => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
||||||
@@ -2512,7 +2505,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I16x8AddSaturateS => {
|
Operator::I16x8AddSatS => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
||||||
@@ -2529,7 +2522,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I8x16AddSaturateU => {
|
Operator::I8x16AddSatU => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
||||||
@@ -2546,7 +2539,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I16x8AddSaturateU => {
|
Operator::I16x8AddSatU => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
||||||
@@ -2603,7 +2596,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I8x16SubSaturateS => {
|
Operator::I8x16SubSatS => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
||||||
@@ -2620,7 +2613,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I16x8SubSaturateS => {
|
Operator::I16x8SubSatS => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
||||||
@@ -2637,7 +2630,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I8x16SubSaturateU => {
|
Operator::I8x16SubSatU => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
let (v1, _) = self.v128_into_i8x16(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
let (v2, _) = self.v128_into_i8x16(v2, i2);
|
||||||
@@ -2654,7 +2647,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I16x8SubSaturateU => {
|
Operator::I16x8SubSatU => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
let (v1, _) = self.v128_into_i16x8(v1, i1);
|
||||||
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
let (v2, _) = self.v128_into_i16x8(v2, i2);
|
||||||
@@ -6975,7 +6968,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
};
|
};
|
||||||
self.state.push1_extra(res, info);
|
self.state.push1_extra(res, info);
|
||||||
}
|
}
|
||||||
Operator::V8x16Swizzle => {
|
Operator::I8x16Swizzle => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let v1 = self.apply_pending_canonicalization(v1, i1);
|
let v1 = self.apply_pending_canonicalization(v1, i1);
|
||||||
let v1 = self
|
let v1 = self
|
||||||
@@ -7043,7 +7036,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::V8x16Shuffle { lanes } => {
|
Operator::I8x16Shuffle { lanes } => {
|
||||||
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
|
||||||
let v1 = self.apply_pending_canonicalization(v1, i1);
|
let v1 = self.apply_pending_canonicalization(v1, i1);
|
||||||
let v1 = self
|
let v1 = self
|
||||||
@@ -7066,7 +7059,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I16x8Load8x8S { ref memarg } => {
|
Operator::V128Load8x8S { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7087,7 +7080,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I16x8Load8x8U { ref memarg } => {
|
Operator::V128Load8x8U { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7108,7 +7101,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I32x4Load16x4S { ref memarg } => {
|
Operator::V128Load16x4S { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7129,7 +7122,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I32x4Load16x4U { ref memarg } => {
|
Operator::V128Load16x4U { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7150,7 +7143,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I64x2Load32x2S { ref memarg } => {
|
Operator::V128Load32x2S { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7171,7 +7164,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::I64x2Load32x2U { ref memarg } => {
|
Operator::V128Load32x2U { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7192,7 +7185,55 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::V8x16LoadSplat { ref memarg } => {
|
Operator::V128Load32Zero { ref memarg } => {
|
||||||
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
|
let effective_address = self.resolve_memory_ptr(
|
||||||
|
memory_index,
|
||||||
|
memarg,
|
||||||
|
self.intrinsics.i32_ptr_ty,
|
||||||
|
offset,
|
||||||
|
4,
|
||||||
|
)?;
|
||||||
|
let elem = self.builder.build_load(effective_address, "");
|
||||||
|
self.annotate_user_memaccess(
|
||||||
|
memory_index,
|
||||||
|
memarg,
|
||||||
|
1,
|
||||||
|
elem.as_instruction_value().unwrap(),
|
||||||
|
)?;
|
||||||
|
let res = self.builder.build_int_z_extend(
|
||||||
|
elem.into_int_value(),
|
||||||
|
self.intrinsics.i128_ty,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
self.state.push1(res);
|
||||||
|
}
|
||||||
|
Operator::V128Load64Zero { ref memarg } => {
|
||||||
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
|
let effective_address = self.resolve_memory_ptr(
|
||||||
|
memory_index,
|
||||||
|
memarg,
|
||||||
|
self.intrinsics.i64_ptr_ty,
|
||||||
|
offset,
|
||||||
|
8,
|
||||||
|
)?;
|
||||||
|
let elem = self.builder.build_load(effective_address, "");
|
||||||
|
self.annotate_user_memaccess(
|
||||||
|
memory_index,
|
||||||
|
memarg,
|
||||||
|
1,
|
||||||
|
elem.as_instruction_value().unwrap(),
|
||||||
|
)?;
|
||||||
|
let res = self.builder.build_int_z_extend(
|
||||||
|
elem.into_int_value(),
|
||||||
|
self.intrinsics.i128_ty,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
self.state.push1(res);
|
||||||
|
}
|
||||||
|
Operator::V128Load8Splat { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7213,7 +7254,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::V16x8LoadSplat { ref memarg } => {
|
Operator::V128Load16Splat { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7234,7 +7275,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::V32x4LoadSplat { ref memarg } => {
|
Operator::V128Load32Splat { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -7255,7 +7296,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
|
||||||
self.state.push1(res);
|
self.state.push1(res);
|
||||||
}
|
}
|
||||||
Operator::V64x2LoadSplat { ref memarg } => {
|
Operator::V128Load64Splat { ref memarg } => {
|
||||||
let offset = self.state.pop1()?.into_int_value();
|
let offset = self.state.pop1()?.into_int_value();
|
||||||
let memory_index = MemoryIndex::from_u32(0);
|
let memory_index = MemoryIndex::from_u32(0);
|
||||||
let effective_address = self.resolve_memory_ptr(
|
let effective_address = self.resolve_memory_ptr(
|
||||||
@@ -9246,8 +9287,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
self.state.push1(old);
|
self.state.push1(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator::MemoryGrow { reserved } => {
|
Operator::MemoryGrow { mem, mem_byte: _ } => {
|
||||||
let memory_index = MemoryIndex::from_u32(reserved);
|
let memory_index = MemoryIndex::from_u32(mem);
|
||||||
let delta = self.state.pop1()?;
|
let delta = self.state.pop1()?;
|
||||||
let grow_fn_ptr = self.ctx.memory_grow(memory_index, self.intrinsics);
|
let grow_fn_ptr = self.ctx.memory_grow(memory_index, self.intrinsics);
|
||||||
let grow = self.builder.build_call(
|
let grow = self.builder.build_call(
|
||||||
@@ -9257,15 +9298,15 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
delta,
|
delta,
|
||||||
self.intrinsics
|
self.intrinsics
|
||||||
.i32_ty
|
.i32_ty
|
||||||
.const_int(reserved.into(), false)
|
.const_int(mem.into(), false)
|
||||||
.as_basic_value_enum(),
|
.as_basic_value_enum(),
|
||||||
],
|
],
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
self.state.push1(grow.try_as_basic_value().left().unwrap());
|
self.state.push1(grow.try_as_basic_value().left().unwrap());
|
||||||
}
|
}
|
||||||
Operator::MemorySize { reserved } => {
|
Operator::MemorySize { mem, mem_byte: _ } => {
|
||||||
let memory_index = MemoryIndex::from_u32(reserved);
|
let memory_index = MemoryIndex::from_u32(mem);
|
||||||
let size_fn_ptr = self.ctx.memory_size(memory_index, self.intrinsics);
|
let size_fn_ptr = self.ctx.memory_size(memory_index, self.intrinsics);
|
||||||
let size = self.builder.build_call(
|
let size = self.builder.build_call(
|
||||||
size_fn_ptr,
|
size_fn_ptr,
|
||||||
@@ -9273,7 +9314,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
|||||||
vmctx.as_basic_value_enum(),
|
vmctx.as_basic_value_enum(),
|
||||||
self.intrinsics
|
self.intrinsics
|
||||||
.i32_ty
|
.i32_ty
|
||||||
.const_int(reserved.into(), false)
|
.const_int(mem.into(), false)
|
||||||
.as_basic_value_enum(),
|
.as_basic_value_enum(),
|
||||||
],
|
],
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-compiler-singlepass"
|
name = "wasmer-compiler-singlepass"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Singlepass compiler for Wasmer WebAssembly runtime"
|
description = "Singlepass compiler for Wasmer WebAssembly runtime"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "compiler", "singlepass"]
|
keywords = ["wasm", "webassembly", "compiler", "singlepass"]
|
||||||
@@ -12,11 +12,11 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"], default-features = false }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"], default-features = false }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4", default-features = false, features = ["std"] }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5", default-features = false, features = ["std"] }
|
||||||
rayon = "1.3"
|
rayon = "1.5"
|
||||||
hashbrown = { version = "0.8", optional = true }
|
hashbrown = { version = "0.9", optional = true }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
more-asserts = "0.2"
|
more-asserts = "0.2"
|
||||||
dynasm = "1.0"
|
dynasm = "1.0"
|
||||||
|
|||||||
@@ -1316,17 +1316,7 @@ impl<'a> FuncGen<'a> {
|
|||||||
self.machine.release_temp_gpr(tmp_bound);
|
self.machine.release_temp_gpr(tmp_bound);
|
||||||
self.machine.release_temp_gpr(tmp_base);
|
self.machine.release_temp_gpr(tmp_base);
|
||||||
|
|
||||||
let align = match memarg.flags & 3 {
|
let align = memarg.align;
|
||||||
0 => 1,
|
|
||||||
1 => 2,
|
|
||||||
2 => 4,
|
|
||||||
3 => 8,
|
|
||||||
_ => {
|
|
||||||
return Err(CodegenError {
|
|
||||||
message: "emit_memory_op align: unreachable value".to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if check_alignment && align != 1 {
|
if check_alignment && align != 1 {
|
||||||
let tmp_aligncheck = self.machine.acquire_temp_gpr().unwrap();
|
let tmp_aligncheck = self.machine.acquire_temp_gpr().unwrap();
|
||||||
self.assembler.emit_mov(
|
self.assembler.emit_mov(
|
||||||
@@ -1336,7 +1326,7 @@ impl<'a> FuncGen<'a> {
|
|||||||
);
|
);
|
||||||
self.assembler.emit_and(
|
self.assembler.emit_and(
|
||||||
Size::S64,
|
Size::S64,
|
||||||
Location::Imm32(align - 1),
|
Location::Imm32((align - 1).into()),
|
||||||
Location::GPR(tmp_aligncheck),
|
Location::GPR(tmp_aligncheck),
|
||||||
);
|
);
|
||||||
self.assembler
|
self.assembler
|
||||||
@@ -5615,8 +5605,8 @@ impl<'a> FuncGen<'a> {
|
|||||||
// TODO: Re-enable interrupt signal check without branching
|
// TODO: Re-enable interrupt signal check without branching
|
||||||
}
|
}
|
||||||
Operator::Nop => {}
|
Operator::Nop => {}
|
||||||
Operator::MemorySize { reserved } => {
|
Operator::MemorySize { mem, mem_byte: _ } => {
|
||||||
let memory_index = MemoryIndex::new(reserved as usize);
|
let memory_index = MemoryIndex::new(mem as usize);
|
||||||
self.assembler.emit_mov(
|
self.assembler.emit_mov(
|
||||||
Size::S64,
|
Size::S64,
|
||||||
Location::Memory(
|
Location::Memory(
|
||||||
@@ -5653,8 +5643,8 @@ impl<'a> FuncGen<'a> {
|
|||||||
self.assembler
|
self.assembler
|
||||||
.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
||||||
}
|
}
|
||||||
Operator::MemoryGrow { reserved } => {
|
Operator::MemoryGrow { mem, mem_byte: _ } => {
|
||||||
let memory_index = MemoryIndex::new(reserved as usize);
|
let memory_index = MemoryIndex::new(mem as usize);
|
||||||
let param_pages = self.value_stack.pop().unwrap();
|
let param_pages = self.value_stack.pop().unwrap();
|
||||||
|
|
||||||
self.machine.release_locations_only_regs(&[param_pages]);
|
self.machine.release_locations_only_regs(&[param_pages]);
|
||||||
@@ -6304,9 +6294,13 @@ impl<'a> FuncGen<'a> {
|
|||||||
self.assembler.emit_label(after);
|
self.assembler.emit_label(after);
|
||||||
}
|
}
|
||||||
Operator::BrTable { ref table } => {
|
Operator::BrTable { ref table } => {
|
||||||
let (targets, default_target) = table.read_table().map_err(|e| CodegenError {
|
let mut targets = table
|
||||||
message: format!("BrTable read_table: {:?}", e),
|
.targets()
|
||||||
})?;
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map_err(|e| CodegenError {
|
||||||
|
message: format!("BrTable read_table: {:?}", e),
|
||||||
|
})?;
|
||||||
|
let default_target = targets.pop().unwrap().0;
|
||||||
let cond = self.pop_value_released();
|
let cond = self.pop_value_released();
|
||||||
let table_label = self.assembler.get_label();
|
let table_label = self.assembler.get_label();
|
||||||
let mut table: Vec<DynamicLabel> = vec![];
|
let mut table: Vec<DynamicLabel> = vec![];
|
||||||
@@ -6334,7 +6328,7 @@ impl<'a> FuncGen<'a> {
|
|||||||
);
|
);
|
||||||
self.assembler.emit_jmp_location(Location::GPR(GPR::RDX));
|
self.assembler.emit_jmp_location(Location::GPR(GPR::RDX));
|
||||||
|
|
||||||
for target in targets.iter() {
|
for (target, _) in targets.iter() {
|
||||||
let label = self.assembler.get_label();
|
let label = self.assembler.get_label();
|
||||||
self.assembler.emit_label(label);
|
self.assembler.emit_label(label);
|
||||||
table.push(label);
|
table.push(label);
|
||||||
@@ -8179,7 +8173,6 @@ impl<'a> FuncGen<'a> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(offset, code)| TrapInformation {
|
.map(|(offset, code)| TrapInformation {
|
||||||
code_offset: offset as u32,
|
code_offset: offset as u32,
|
||||||
source_loc: Default::default(),
|
|
||||||
trap_code: code,
|
trap_code: code,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ impl Compiler for SinglepassCompiler {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect();
|
.collect();
|
||||||
let functions = function_body_inputs
|
let functions = function_body_inputs
|
||||||
.into_iter()
|
.iter()
|
||||||
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|(i, input)| {
|
.map(|(i, input)| {
|
||||||
@@ -82,10 +82,7 @@ impl Compiler for SinglepassCompiler {
|
|||||||
let mut locals = vec![];
|
let mut locals = vec![];
|
||||||
let num_locals = reader.read_local_count().map_err(to_compile_error)?;
|
let num_locals = reader.read_local_count().map_err(to_compile_error)?;
|
||||||
for _ in 0..num_locals {
|
for _ in 0..num_locals {
|
||||||
let mut counter = 0;
|
let (count, ty) = reader.read_local_decl().map_err(to_compile_error)?;
|
||||||
let (count, ty) = reader
|
|
||||||
.read_local_decl(&mut counter)
|
|
||||||
.map_err(to_compile_error)?;
|
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
locals.push(ty);
|
locals.push(ty);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-compiler"
|
name = "wasmer-compiler"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Base compiler abstraction for Wasmer WebAssembly runtime"
|
description = "Base compiler abstraction for Wasmer WebAssembly runtime"
|
||||||
categories = ["wasm", "no-std"]
|
categories = ["wasm", "no-std"]
|
||||||
keywords = ["wasm", "webassembly", "compiler"]
|
keywords = ["wasm", "webassembly", "compiler"]
|
||||||
@@ -11,12 +11,12 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4", default-features = false }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5", default-features = false }
|
||||||
wasmparser = { version = "0.57", optional = true, default-features = false }
|
wasmparser = { version = "0.65", optional = true, default-features = false }
|
||||||
target-lexicon = { version = "0.10", default-features = false }
|
target-lexicon = { version = "0.11", default-features = false }
|
||||||
enumset = "1.0"
|
enumset = "1.0"
|
||||||
hashbrown = { version = "0.8", optional = true }
|
hashbrown = { version = "0.9", optional = true }
|
||||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
serde_bytes = { version = "0.11", optional = true }
|
serde_bytes = { version = "0.11", optional = true }
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use crate::ModuleTranslationState;
|
|||||||
use crate::SectionIndex;
|
use crate::SectionIndex;
|
||||||
use wasmer_types::entity::PrimaryMap;
|
use wasmer_types::entity::PrimaryMap;
|
||||||
use wasmer_types::{Features, FunctionIndex, LocalFunctionIndex, SignatureIndex};
|
use wasmer_types::{Features, FunctionIndex, LocalFunctionIndex, SignatureIndex};
|
||||||
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
use wasmparser::{Validator, WasmFeatures};
|
||||||
|
|
||||||
/// The compiler configuration options.
|
/// The compiler configuration options.
|
||||||
pub trait CompilerConfig {
|
pub trait CompilerConfig {
|
||||||
@@ -58,17 +58,24 @@ pub trait Compiler {
|
|||||||
features: &Features,
|
features: &Features,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
let config = ValidatingParserConfig {
|
let mut validator = Validator::new();
|
||||||
operator_config: OperatorValidatorConfig {
|
let wasm_features = WasmFeatures {
|
||||||
enable_threads: features.threads,
|
bulk_memory: features.bulk_memory,
|
||||||
enable_reference_types: features.reference_types,
|
threads: features.threads,
|
||||||
enable_bulk_memory: features.bulk_memory,
|
reference_types: features.reference_types,
|
||||||
enable_tail_call: false,
|
multi_value: features.multi_value,
|
||||||
enable_simd: features.simd,
|
simd: features.simd,
|
||||||
enable_multi_value: features.multi_value,
|
tail_call: features.tail_call,
|
||||||
},
|
module_linking: features.module_linking,
|
||||||
|
multi_memory: features.multi_memory,
|
||||||
|
memory64: features.memory64,
|
||||||
|
deterministic_only: false,
|
||||||
};
|
};
|
||||||
validate(data, Some(config)).map_err(|e| CompileError::Validate(format!("{}", e)))
|
validator.wasm_features(wasm_features);
|
||||||
|
validator
|
||||||
|
.validate_all(data)
|
||||||
|
.map_err(|e| CompileError::Validate(format!("{}", e)))?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compiles a parsed module.
|
/// Compiles a parsed module.
|
||||||
|
|||||||
@@ -94,13 +94,15 @@ impl<'a> MiddlewareBinaryReader<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a `count` indicating the number of times to call `read_local_decl`.
|
/// Read a `count` indicating the number of times to call `read_local_decl`.
|
||||||
pub fn read_local_count(&mut self) -> WpResult<usize> {
|
pub fn read_local_count(&mut self) -> WpResult<u32> {
|
||||||
self.state.inner.read_local_count()
|
self.state.inner.read_var_u32()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a `(count, value_type)` declaration of local variables of the same type.
|
/// Read a `(count, value_type)` declaration of local variables of the same type.
|
||||||
pub fn read_local_decl(&mut self, locals_total: &mut usize) -> WpResult<(u32, Type)> {
|
pub fn read_local_decl(&mut self) -> WpResult<(u32, Type)> {
|
||||||
self.state.inner.read_local_decl(locals_total)
|
let count = self.state.inner.read_var_u32()?;
|
||||||
|
let ty = self.state.inner.read_type()?;
|
||||||
|
Ok((count, ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the next available `Operator`.
|
/// Reads the next available `Operator`.
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
use super::environ::ModuleEnvironment;
|
use super::environ::ModuleEnvironment;
|
||||||
use super::error::to_wasm_error;
|
use super::error::to_wasm_error;
|
||||||
use super::sections::{
|
use super::sections::{
|
||||||
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
parse_data_section, parse_element_section, parse_export_section, parse_function_section,
|
||||||
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
parse_global_section, parse_import_section, parse_memory_section, parse_name_section,
|
||||||
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
|
parse_start_section, parse_table_section, parse_type_section,
|
||||||
};
|
};
|
||||||
use super::state::ModuleTranslationState;
|
use super::state::ModuleTranslationState;
|
||||||
use crate::WasmResult;
|
use crate::WasmResult;
|
||||||
use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
use wasmparser::{NameSectionReader, Parser, Payload};
|
||||||
|
|
||||||
/// Translate a sequence of bytes forming a valid Wasm binary into a
|
/// Translate a sequence of bytes forming a valid Wasm binary into a
|
||||||
/// parsed ModuleInfo `ModuleTranslationState`.
|
/// parsed ModuleInfo `ModuleTranslationState`.
|
||||||
@@ -20,75 +20,88 @@ pub fn translate_module<'data>(
|
|||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
environ: &mut ModuleEnvironment<'data>,
|
environ: &mut ModuleEnvironment<'data>,
|
||||||
) -> WasmResult<ModuleTranslationState> {
|
) -> WasmResult<ModuleTranslationState> {
|
||||||
let mut reader = ModuleReader::new(data).map_err(to_wasm_error)?;
|
|
||||||
let mut module_translation_state = ModuleTranslationState::new();
|
let mut module_translation_state = ModuleTranslationState::new();
|
||||||
|
|
||||||
while !reader.eof() {
|
for payload in Parser::new(0).parse_all(data) {
|
||||||
let section = reader.read().map_err(to_wasm_error)?;
|
match payload.map_err(to_wasm_error)? {
|
||||||
match section.content().map_err(to_wasm_error)? {
|
Payload::Version { .. } | Payload::End => {}
|
||||||
SectionContent::Type(types) => {
|
|
||||||
|
Payload::TypeSection(types) => {
|
||||||
parse_type_section(types, &mut module_translation_state, environ)?;
|
parse_type_section(types, &mut module_translation_state, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Import(imports) => {
|
Payload::ImportSection(imports) => {
|
||||||
parse_import_section(imports, environ)?;
|
parse_import_section(imports, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Function(functions) => {
|
Payload::FunctionSection(functions) => {
|
||||||
parse_function_section(functions, environ)?;
|
parse_function_section(functions, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Table(tables) => {
|
Payload::TableSection(tables) => {
|
||||||
parse_table_section(tables, environ)?;
|
parse_table_section(tables, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Memory(memories) => {
|
Payload::MemorySection(memories) => {
|
||||||
parse_memory_section(memories, environ)?;
|
parse_memory_section(memories, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Global(globals) => {
|
Payload::GlobalSection(globals) => {
|
||||||
parse_global_section(globals, environ)?;
|
parse_global_section(globals, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Export(exports) => {
|
Payload::ExportSection(exports) => {
|
||||||
parse_export_section(exports, environ)?;
|
parse_export_section(exports, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Start(start) => {
|
Payload::StartSection { func, .. } => {
|
||||||
parse_start_section(start, environ)?;
|
parse_start_section(func, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Element(elements) => {
|
Payload::ElementSection(elements) => {
|
||||||
parse_element_section(elements, environ)?;
|
parse_element_section(elements, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Code(code) => {
|
Payload::CodeSectionStart { .. } => {}
|
||||||
parse_code_section(code, &module_translation_state, environ)?;
|
Payload::CodeSectionEntry(code) => {
|
||||||
|
let mut code = code.get_binary_reader();
|
||||||
|
let size = code.bytes_remaining();
|
||||||
|
let offset = code.original_position();
|
||||||
|
environ.define_function_body(
|
||||||
|
&module_translation_state,
|
||||||
|
code.read_bytes(size).map_err(to_wasm_error)?,
|
||||||
|
offset,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Data(data) => {
|
Payload::DataSection(data) => {
|
||||||
parse_data_section(data, environ)?;
|
parse_data_section(data, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::DataCount(count) => {
|
Payload::DataCountSection { count, .. } => {
|
||||||
environ.reserve_passive_data(count)?;
|
environ.reserve_passive_data(count)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Custom {
|
Payload::ModuleSection(_)
|
||||||
name,
|
| Payload::InstanceSection(_)
|
||||||
binary,
|
| Payload::AliasSection(_)
|
||||||
content,
|
| Payload::ModuleCodeSectionStart { .. }
|
||||||
} => match content {
|
| Payload::ModuleCodeSectionEntry { .. } => {
|
||||||
Some(CustomSectionContent::Name(names)) => {
|
unimplemented!("module linking not implemented yet")
|
||||||
parse_name_section(names, environ)?;
|
}
|
||||||
}
|
|
||||||
_ => {
|
Payload::CustomSection {
|
||||||
let mut reader = binary.clone();
|
name: "name",
|
||||||
let len = reader.bytes_remaining();
|
data,
|
||||||
let payload = reader.read_bytes(len).map_err(to_wasm_error)?;
|
data_offset,
|
||||||
environ.custom_section(name, payload)?;
|
} => parse_name_section(
|
||||||
}
|
NameSectionReader::new(data, data_offset).map_err(to_wasm_error)?,
|
||||||
},
|
environ,
|
||||||
|
)?,
|
||||||
|
|
||||||
|
Payload::CustomSection { name, data, .. } => environ.custom_section(name, data)?,
|
||||||
|
|
||||||
|
Payload::UnknownSection { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,11 @@ use wasmer_types::{
|
|||||||
MemoryIndex, MemoryType, Pages, SignatureIndex, TableIndex, TableType, Type, V128,
|
MemoryIndex, MemoryType, Pages, SignatureIndex, TableIndex, TableType, Type, V128,
|
||||||
};
|
};
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems,
|
self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind,
|
||||||
ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind,
|
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType as WPFunctionType,
|
||||||
FuncType as WPFunctionType, FunctionSectionReader, GlobalSectionReader,
|
FunctionSectionReader, GlobalSectionReader, GlobalType as WPGlobalType, ImportSectionEntryType,
|
||||||
GlobalType as WPGlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader,
|
ImportSectionReader, MemorySectionReader, MemoryType as WPMemoryType, NameSectionReader,
|
||||||
MemoryType as WPMemoryType, NameSectionReader, Naming, NamingReader, Operator,
|
Naming, NamingReader, Operator, TableSectionReader, TypeDef, TypeSectionReader,
|
||||||
TableSectionReader, TypeSectionReader,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper function translating wasmparser types to Wasm Type.
|
/// Helper function translating wasmparser types to Wasm Type.
|
||||||
@@ -61,25 +60,29 @@ pub fn parse_type_section(
|
|||||||
environ.reserve_signatures(count)?;
|
environ.reserve_signatures(count)?;
|
||||||
|
|
||||||
for entry in types {
|
for entry in types {
|
||||||
let WPFunctionType { params, returns } = entry.map_err(to_wasm_error)?;
|
if let Ok(TypeDef::Func(WPFunctionType { params, returns })) = entry {
|
||||||
let sig_params: Vec<Type> = params
|
let sig_params: Vec<Type> = params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| {
|
.map(|ty| {
|
||||||
wptype_to_type(*ty)
|
wptype_to_type(*ty)
|
||||||
.expect("only numeric types are supported in function signatures")
|
.expect("only numeric types are supported in function signatures")
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let sig_returns: Vec<Type> = returns
|
let sig_returns: Vec<Type> = returns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| {
|
.map(|ty| {
|
||||||
wptype_to_type(*ty)
|
wptype_to_type(*ty)
|
||||||
.expect("only numeric types are supported in function signatures")
|
.expect("only numeric types are supported in function signatures")
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let sig = FunctionType::new(sig_params, sig_returns);
|
let sig = FunctionType::new(sig_params, sig_returns);
|
||||||
environ.declare_signature(sig)?;
|
environ.declare_signature(sig)?;
|
||||||
module_translation_state.wasm_types.push((params, returns));
|
module_translation_state.wasm_types.push((params, returns));
|
||||||
|
} else {
|
||||||
|
unimplemented!("module linking not implemented yet")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,10 +103,13 @@ pub fn parse_import_section<'data>(
|
|||||||
environ.declare_func_import(
|
environ.declare_func_import(
|
||||||
SignatureIndex::from_u32(sig),
|
SignatureIndex::from_u32(sig),
|
||||||
module_name,
|
module_name,
|
||||||
field_name,
|
field_name.unwrap_or_default(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
ImportSectionEntryType::Memory(WPMemoryType {
|
ImportSectionEntryType::Module(_sig) | ImportSectionEntryType::Instance(_sig) => {
|
||||||
|
unimplemented!("module linking not implemented yet")
|
||||||
|
}
|
||||||
|
ImportSectionEntryType::Memory(WPMemoryType::M32 {
|
||||||
limits: ref memlimits,
|
limits: ref memlimits,
|
||||||
shared,
|
shared,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -114,9 +120,12 @@ pub fn parse_import_section<'data>(
|
|||||||
shared,
|
shared,
|
||||||
},
|
},
|
||||||
module_name,
|
module_name,
|
||||||
field_name,
|
field_name.unwrap_or_default(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
ImportSectionEntryType::Memory(WPMemoryType::M64 { .. }) => {
|
||||||
|
unimplemented!("64bit memory not implemented yet")
|
||||||
|
}
|
||||||
ImportSectionEntryType::Global(ref ty) => {
|
ImportSectionEntryType::Global(ref ty) => {
|
||||||
environ.declare_global_import(
|
environ.declare_global_import(
|
||||||
GlobalType {
|
GlobalType {
|
||||||
@@ -124,7 +133,7 @@ pub fn parse_import_section<'data>(
|
|||||||
mutability: ty.mutable.into(),
|
mutability: ty.mutable.into(),
|
||||||
},
|
},
|
||||||
module_name,
|
module_name,
|
||||||
field_name,
|
field_name.unwrap_or_default(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
ImportSectionEntryType::Table(ref tab) => {
|
ImportSectionEntryType::Table(ref tab) => {
|
||||||
@@ -135,7 +144,7 @@ pub fn parse_import_section<'data>(
|
|||||||
maximum: tab.limits.maximum,
|
maximum: tab.limits.maximum,
|
||||||
},
|
},
|
||||||
module_name,
|
module_name,
|
||||||
field_name,
|
field_name.unwrap_or_default(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,11 +203,16 @@ pub fn parse_memory_section(
|
|||||||
|
|
||||||
for entry in memories {
|
for entry in memories {
|
||||||
let memory = entry.map_err(to_wasm_error)?;
|
let memory = entry.map_err(to_wasm_error)?;
|
||||||
environ.declare_memory(MemoryType {
|
match memory {
|
||||||
minimum: Pages(memory.limits.initial),
|
WPMemoryType::M32 { limits, shared } => {
|
||||||
maximum: memory.limits.maximum.map(Pages),
|
environ.declare_memory(MemoryType {
|
||||||
shared: memory.shared,
|
minimum: Pages(limits.initial),
|
||||||
})?;
|
maximum: limits.maximum.map(Pages),
|
||||||
|
shared: shared,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
WPMemoryType::M64 { .. } => unimplemented!("64bit memory not implemented yet"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -281,6 +295,9 @@ pub fn parse_export_section<'data>(
|
|||||||
ExternalKind::Global => {
|
ExternalKind::Global => {
|
||||||
environ.declare_global_export(GlobalIndex::new(index), field)?
|
environ.declare_global_export(GlobalIndex::new(index), field)?
|
||||||
}
|
}
|
||||||
|
ExternalKind::Type | ExternalKind::Module | ExternalKind::Instance => {
|
||||||
|
unimplemented!("module linking not implemented yet")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,25 +376,6 @@ pub fn parse_element_section<'data>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the Code section of the wasm module.
|
|
||||||
pub fn parse_code_section<'data>(
|
|
||||||
code: CodeSectionReader<'data>,
|
|
||||||
module_translation_state: &ModuleTranslationState,
|
|
||||||
environ: &mut ModuleEnvironment<'data>,
|
|
||||||
) -> WasmResult<()> {
|
|
||||||
for body in code {
|
|
||||||
let mut reader = body.map_err(to_wasm_error)?.get_binary_reader();
|
|
||||||
let size = reader.bytes_remaining();
|
|
||||||
let offset = reader.original_position();
|
|
||||||
environ.define_function_body(
|
|
||||||
module_translation_state,
|
|
||||||
reader.read_bytes(size).map_err(to_wasm_error)?,
|
|
||||||
offset,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses the Data section of the wasm module.
|
/// Parses the Data section of the wasm module.
|
||||||
pub fn parse_data_section<'data>(
|
pub fn parse_data_section<'data>(
|
||||||
data: DataSectionReader<'data>,
|
data: DataSectionReader<'data>,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::sourceloc::SourceLoc;
|
|
||||||
use crate::CodeOffset;
|
use crate::CodeOffset;
|
||||||
#[cfg(feature = "enable-serde")]
|
#[cfg(feature = "enable-serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -10,8 +9,6 @@ use wasmer_vm::TrapCode;
|
|||||||
pub struct TrapInformation {
|
pub struct TrapInformation {
|
||||||
/// The offset of the trapping instruction in native code. It is relative to the beginning of the function.
|
/// The offset of the trapping instruction in native code. It is relative to the beginning of the function.
|
||||||
pub code_offset: CodeOffset,
|
pub code_offset: CodeOffset,
|
||||||
/// Location of trapping instruction in WebAssembly binary module.
|
|
||||||
pub source_loc: SourceLoc,
|
|
||||||
/// Code of the trap.
|
/// Code of the trap.
|
||||||
pub trap_code: TrapCode,
|
pub trap_code: TrapCode,
|
||||||
}
|
}
|
||||||
|
|||||||
42
lib/deprecated/runtime-core/Cargo.lock
generated
42
lib/deprecated/runtime-core/Cargo.lock
generated
@@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"object 0.20.0",
|
"object 0.20.0",
|
||||||
@@ -81,7 +81,7 @@ dependencies = [
|
|||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
"crypto-mac",
|
"crypto-mac",
|
||||||
"digest",
|
"digest",
|
||||||
@@ -105,6 +105,12 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloudabi"
|
name = "cloudabi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -192,7 +198,7 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -213,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
@@ -227,7 +233,7 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
]
|
]
|
||||||
@@ -239,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -379,7 +385,7 @@ version = "0.1.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
@@ -481,11 +487,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.7"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66"
|
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -552,7 +558,7 @@ version = "0.4.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -668,7 +674,7 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"cloudabi",
|
"cloudabi",
|
||||||
"instant",
|
"instant",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1015,7 +1021,7 @@ version = "3.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"rand",
|
"rand",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
@@ -1058,7 +1064,7 @@ version = "0.1.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd"
|
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
@@ -1111,7 +1117,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||||||
name = "wasmer"
|
name = "wasmer"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
@@ -1245,7 +1251,7 @@ name = "wasmer-engine-jit"
|
|||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"region",
|
"region",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
@@ -1261,7 +1267,7 @@ name = "wasmer-engine-native"
|
|||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"leb128",
|
"leb128",
|
||||||
"libloading",
|
"libloading",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1317,7 +1323,7 @@ version = "1.0.0-alpha4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"libc",
|
"libc",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ edition = "2018"
|
|||||||
maintenance = { status = "deprecated" }
|
maintenance = { status = "deprecated" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-types = { path = "../../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
wasmer = { path = "../../api", version = "1.0.0-alpha4" }
|
wasmer = { path = "../../api", version = "1.0.0-alpha5" }
|
||||||
wasmer-cache = { path = "../../cache", version = "1.0.0-alpha4" }
|
wasmer-cache = { path = "../../cache", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler = { path = "../../compiler", version = "1.0.0-alpha4", features = ["translator"] }
|
wasmer-compiler = { path = "../../compiler", version = "1.0.0-alpha5", features = ["translator"] }
|
||||||
wasmer-compiler-llvm = { path = "../../compiler-llvm", version = "1.0.0-alpha4", optional = true }
|
wasmer-compiler-llvm = { path = "../../compiler-llvm", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-compiler-cranelift = { path = "../../compiler-cranelift", version = "1.0.0-alpha4", optional = true }
|
wasmer-compiler-cranelift = { path = "../../compiler-cranelift", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-compiler-singlepass = { path = "../../compiler-singlepass", version = "1.0.0-alpha4", optional = true }
|
wasmer-compiler-singlepass = { path = "../../compiler-singlepass", version = "1.0.0-alpha5", optional = true }
|
||||||
wasmer-engine = { path = "../../engine", version = "1.0.0-alpha4" }
|
wasmer-engine = { path = "../../engine", version = "1.0.0-alpha5" }
|
||||||
wasmer-engine-jit = { path = "../../engine-jit", version = "1.0.0-alpha4" }
|
wasmer-engine-jit = { path = "../../engine-jit", version = "1.0.0-alpha5" }
|
||||||
wasmer-vm = { path = "../../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../../vm", version = "1.0.0-alpha5" }
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -102,14 +102,14 @@ impl Module {
|
|||||||
// Properly drop the empty `vm::Ctx`
|
// Properly drop the empty `vm::Ctx`
|
||||||
// created by the host function.
|
// created by the host function.
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::drop_in_place::<vm::Ctx>(function.vmctx as _);
|
ptr::drop_in_place::<vm::Ctx>(function.vmctx.host_env as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the pointer to `VMContext`,
|
// Update the pointer to `VMContext`,
|
||||||
// which is actually a `vm::Ctx`
|
// which is actually a `vm::Ctx`
|
||||||
// pointer, to fallback on the
|
// pointer, to fallback on the
|
||||||
// environment hack.
|
// environment hack.
|
||||||
function.vmctx = pre_instance.vmctx_ptr() as _;
|
function.vmctx.host_env = pre_instance.vmctx_ptr() as _;
|
||||||
}
|
}
|
||||||
// `function` is a dynamic host function
|
// `function` is a dynamic host function
|
||||||
// constructed with
|
// constructed with
|
||||||
@@ -147,13 +147,13 @@ impl Module {
|
|||||||
new::wasmer_vm::VMDynamicFunctionContext<
|
new::wasmer_vm::VMDynamicFunctionContext<
|
||||||
VMDynamicFunctionWithEnv<DynamicCtx>,
|
VMDynamicFunctionWithEnv<DynamicCtx>,
|
||||||
>,
|
>,
|
||||||
> = unsafe { Box::from_raw(function.vmctx as *mut _) };
|
> = unsafe { Box::from_raw(function.vmctx.host_env as *mut _) };
|
||||||
|
|
||||||
// Replace the environment by ours.
|
// Replace the environment by ours.
|
||||||
vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx();
|
vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx();
|
||||||
|
|
||||||
// … without anyone noticing…
|
// … without anyone noticing…
|
||||||
function.vmctx = Box::into_raw(vmctx) as _;
|
function.vmctx.host_env = Box::into_raw(vmctx) as _;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
lib/deprecated/runtime/Cargo.lock
generated
42
lib/deprecated/runtime/Cargo.lock
generated
@@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"object 0.20.0",
|
"object 0.20.0",
|
||||||
@@ -81,7 +81,7 @@ dependencies = [
|
|||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
"crypto-mac",
|
"crypto-mac",
|
||||||
"digest",
|
"digest",
|
||||||
@@ -105,6 +105,12 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloudabi"
|
name = "cloudabi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -192,7 +198,7 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -213,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
@@ -227,7 +233,7 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
]
|
]
|
||||||
@@ -239,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -379,7 +385,7 @@ version = "0.1.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
@@ -481,11 +487,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.7"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66"
|
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -552,7 +558,7 @@ version = "0.4.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -668,7 +674,7 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"cloudabi",
|
"cloudabi",
|
||||||
"instant",
|
"instant",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1015,7 +1021,7 @@ version = "3.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"rand",
|
"rand",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
@@ -1058,7 +1064,7 @@ version = "0.1.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd"
|
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
@@ -1111,7 +1117,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||||||
name = "wasmer"
|
name = "wasmer"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
@@ -1234,7 +1240,7 @@ name = "wasmer-engine-jit"
|
|||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"region",
|
"region",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
@@ -1250,7 +1256,7 @@ name = "wasmer-engine-native"
|
|||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"leb128",
|
"leb128",
|
||||||
"libloading",
|
"libloading",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1313,7 +1319,7 @@ version = "1.0.0-alpha4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"libc",
|
"libc",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-emscripten"
|
name = "wasmer-emscripten"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Emscripten implementation library for Wasmer WebAssembly runtime"
|
description = "Emscripten implementation library for Wasmer WebAssembly runtime"
|
||||||
categories = ["wasm", "os"]
|
categories = ["wasm", "os"]
|
||||||
keywords = ["wasm", "webassembly", "abi", "emscripten", "posix"]
|
keywords = ["wasm", "webassembly", "abi", "emscripten", "posix"]
|
||||||
@@ -13,10 +13,10 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.3"
|
byteorder = "1.3"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
libc = "^0.2.69"
|
libc = "^0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
wasmer = { path = "../api", version = "1.0.0-alpha4", default-features = false }
|
wasmer = { path = "../api", version = "1.0.0-alpha5", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
getrandom = "0.1"
|
getrandom = "0.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-engine-jit"
|
name = "wasmer-engine-jit"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer JIT Engine"
|
description = "Wasmer JIT Engine"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "engine", "jit"]
|
keywords = ["wasm", "webassembly", "engine", "jit"]
|
||||||
@@ -11,10 +11,10 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"] }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"] }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
|
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
|
||||||
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
||||||
region = "2.2"
|
region = "2.2"
|
||||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ use wasmer_compiler::{CompileError, Features, Triple};
|
|||||||
#[cfg(feature = "compiler")]
|
#[cfg(feature = "compiler")]
|
||||||
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment};
|
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment};
|
||||||
use wasmer_engine::{
|
use wasmer_engine::{
|
||||||
register_frame_info, Artifact, DeserializeError, GlobalFrameInfoRegistration, SerializeError,
|
register_frame_info, Artifact, DeserializeError, FunctionExtent, GlobalFrameInfoRegistration,
|
||||||
|
SerializeError,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "compiler")]
|
#[cfg(feature = "compiler")]
|
||||||
use wasmer_engine::{Engine, SerializableFunctionFrameInfo, Tunables};
|
use wasmer_engine::{Engine, SerializableFunctionFrameInfo, Tunables};
|
||||||
@@ -32,6 +33,7 @@ pub struct JITArtifact {
|
|||||||
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
|
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
|
||||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||||
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
|
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
|
||||||
|
finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITArtifact {
|
impl JITArtifact {
|
||||||
@@ -203,7 +205,16 @@ impl JITArtifact {
|
|||||||
|
|
||||||
inner_jit.publish_eh_frame(eh_frame)?;
|
inner_jit.publish_eh_frame(eh_frame)?;
|
||||||
|
|
||||||
let finished_functions = finished_functions.into_boxed_slice();
|
let finished_function_lengths = finished_functions
|
||||||
|
.values()
|
||||||
|
.map(|extent| extent.length)
|
||||||
|
.collect::<PrimaryMap<LocalFunctionIndex, usize>>()
|
||||||
|
.into_boxed_slice();
|
||||||
|
let finished_functions = finished_functions
|
||||||
|
.values()
|
||||||
|
.map(|extent| extent.ptr)
|
||||||
|
.collect::<PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>>()
|
||||||
|
.into_boxed_slice();
|
||||||
let finished_function_call_trampolines =
|
let finished_function_call_trampolines =
|
||||||
finished_function_call_trampolines.into_boxed_slice();
|
finished_function_call_trampolines.into_boxed_slice();
|
||||||
let finished_dynamic_function_trampolines =
|
let finished_dynamic_function_trampolines =
|
||||||
@@ -217,6 +228,7 @@ impl JITArtifact {
|
|||||||
finished_dynamic_function_trampolines,
|
finished_dynamic_function_trampolines,
|
||||||
signatures,
|
signatures,
|
||||||
frame_info_registration: Mutex::new(None),
|
frame_info_registration: Mutex::new(None),
|
||||||
|
finished_function_lengths,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,11 +259,19 @@ impl Artifact for JITArtifact {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let finished_function_extents = self
|
||||||
|
.finished_functions
|
||||||
|
.values()
|
||||||
|
.copied()
|
||||||
|
.zip(self.finished_function_lengths.values().copied())
|
||||||
|
.map(|(ptr, length)| FunctionExtent { ptr, length })
|
||||||
|
.collect::<PrimaryMap<LocalFunctionIndex, _>>()
|
||||||
|
.into_boxed_slice();
|
||||||
|
|
||||||
let frame_infos = &self.serializable.compilation.function_frame_info;
|
let frame_infos = &self.serializable.compilation.function_frame_info;
|
||||||
let finished_functions = &self.finished_functions;
|
|
||||||
*info = register_frame_info(
|
*info = register_frame_info(
|
||||||
self.serializable.compile_info.module.clone(),
|
self.serializable.compile_info.module.clone(),
|
||||||
finished_functions,
|
&finished_function_extents,
|
||||||
frame_infos.clone(),
|
frame_infos.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -280,7 +300,6 @@ impl Artifact for JITArtifact {
|
|||||||
&self.finished_function_call_trampolines
|
&self.finished_function_call_trampolines
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return *const instead of *mut
|
|
||||||
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
|
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
|
||||||
&self.finished_dynamic_function_trampolines
|
&self.finished_dynamic_function_trampolines
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use wasmer_compiler::Compiler;
|
|||||||
use wasmer_compiler::{
|
use wasmer_compiler::{
|
||||||
CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, Target,
|
CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, Target,
|
||||||
};
|
};
|
||||||
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
|
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, FunctionExtent, Tunables};
|
||||||
use wasmer_types::entity::PrimaryMap;
|
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};
|
||||||
@@ -193,7 +193,7 @@ impl JITEngineInner {
|
|||||||
custom_sections: &PrimaryMap<SectionIndex, CustomSection>,
|
custom_sections: &PrimaryMap<SectionIndex, CustomSection>,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>,
|
PrimaryMap<LocalFunctionIndex, FunctionExtent>,
|
||||||
PrimaryMap<SignatureIndex, VMTrampoline>,
|
PrimaryMap<SignatureIndex, VMTrampoline>,
|
||||||
PrimaryMap<FunctionIndex, FunctionBodyPtr>,
|
PrimaryMap<FunctionIndex, FunctionBodyPtr>,
|
||||||
PrimaryMap<SectionIndex, SectionBodyPtr>,
|
PrimaryMap<SectionIndex, SectionBodyPtr>,
|
||||||
@@ -228,7 +228,10 @@ impl JITEngineInner {
|
|||||||
|
|
||||||
let allocated_functions_result = allocated_functions
|
let allocated_functions_result = allocated_functions
|
||||||
.drain(0..functions.len())
|
.drain(0..functions.len())
|
||||||
.map(|slice| FunctionBodyPtr(slice as *mut [_]))
|
.map(|slice| FunctionExtent {
|
||||||
|
ptr: FunctionBodyPtr(slice.as_ptr()),
|
||||||
|
length: slice.len(),
|
||||||
|
})
|
||||||
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
|
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
|
||||||
|
|
||||||
let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
|
let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
|
||||||
@@ -244,7 +247,7 @@ impl JITEngineInner {
|
|||||||
|
|
||||||
let allocated_dynamic_function_trampolines = allocated_functions
|
let allocated_dynamic_function_trampolines = allocated_functions
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|slice| FunctionBodyPtr(slice as *mut [_]))
|
.map(|slice| FunctionBodyPtr(slice.as_ptr()))
|
||||||
.collect::<PrimaryMap<FunctionIndex, _>>();
|
.collect::<PrimaryMap<FunctionIndex, _>>();
|
||||||
|
|
||||||
let mut exec_iter = allocated_executable_sections.iter();
|
let mut exec_iter = allocated_executable_sections.iter();
|
||||||
|
|||||||
@@ -5,23 +5,21 @@ use wasmer_compiler::{
|
|||||||
JumpTable, JumpTableOffsets, Relocation, RelocationKind, RelocationTarget, Relocations,
|
JumpTable, JumpTableOffsets, Relocation, RelocationKind, RelocationTarget, Relocations,
|
||||||
SectionIndex,
|
SectionIndex,
|
||||||
};
|
};
|
||||||
|
use wasmer_engine::FunctionExtent;
|
||||||
use wasmer_types::entity::{EntityRef, PrimaryMap};
|
use wasmer_types::entity::{EntityRef, PrimaryMap};
|
||||||
use wasmer_types::LocalFunctionIndex;
|
use wasmer_types::LocalFunctionIndex;
|
||||||
use wasmer_vm::ModuleInfo;
|
use wasmer_vm::ModuleInfo;
|
||||||
use wasmer_vm::{FunctionBodyPtr, SectionBodyPtr, VMFunctionBody};
|
use wasmer_vm::SectionBodyPtr;
|
||||||
|
|
||||||
fn apply_relocation(
|
fn apply_relocation(
|
||||||
body: usize,
|
body: usize,
|
||||||
r: &Relocation,
|
r: &Relocation,
|
||||||
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>,
|
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
|
||||||
jt_offsets: &PrimaryMap<LocalFunctionIndex, JumpTableOffsets>,
|
jt_offsets: &PrimaryMap<LocalFunctionIndex, JumpTableOffsets>,
|
||||||
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
|
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
|
||||||
) {
|
) {
|
||||||
let target_func_address: usize = match r.reloc_target {
|
let target_func_address: usize = match r.reloc_target {
|
||||||
RelocationTarget::LocalFunc(index) => {
|
RelocationTarget::LocalFunc(index) => *allocated_functions[index].ptr as usize,
|
||||||
let fatptr: *const [VMFunctionBody] = allocated_functions[index].0;
|
|
||||||
fatptr as *const VMFunctionBody as usize
|
|
||||||
}
|
|
||||||
RelocationTarget::LibCall(libcall) => libcall.function_pointer(),
|
RelocationTarget::LibCall(libcall) => libcall.function_pointer(),
|
||||||
RelocationTarget::CustomSection(custom_section) => {
|
RelocationTarget::CustomSection(custom_section) => {
|
||||||
*allocated_sections[custom_section] as usize
|
*allocated_sections[custom_section] as usize
|
||||||
@@ -31,8 +29,7 @@ fn apply_relocation(
|
|||||||
.get(func_index)
|
.get(func_index)
|
||||||
.and_then(|ofs| ofs.get(JumpTable::new(jt.index())))
|
.and_then(|ofs| ofs.get(JumpTable::new(jt.index())))
|
||||||
.expect("func jump table");
|
.expect("func jump table");
|
||||||
let fatptr: *const [VMFunctionBody] = allocated_functions[func_index].0;
|
*allocated_functions[func_index].ptr as usize + offset as usize
|
||||||
fatptr as *const VMFunctionBody as usize + offset as usize
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,7 +66,7 @@ fn apply_relocation(
|
|||||||
/// required relocations and jump tables.
|
/// required relocations and jump tables.
|
||||||
pub fn link_module(
|
pub fn link_module(
|
||||||
_module: &ModuleInfo,
|
_module: &ModuleInfo,
|
||||||
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>,
|
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
|
||||||
jt_offsets: &PrimaryMap<LocalFunctionIndex, JumpTableOffsets>,
|
jt_offsets: &PrimaryMap<LocalFunctionIndex, JumpTableOffsets>,
|
||||||
function_relocations: Relocations,
|
function_relocations: Relocations,
|
||||||
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
|
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
|
||||||
@@ -81,9 +78,8 @@ pub fn link_module(
|
|||||||
apply_relocation(body, r, allocated_functions, jt_offsets, allocated_sections);
|
apply_relocation(body, r, allocated_functions, jt_offsets, allocated_sections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i, function_relocs) in function_relocations.into_iter() {
|
for (i, function_relocs) in function_relocations.iter() {
|
||||||
let fatptr: *const [VMFunctionBody] = allocated_functions[i].0;
|
let body = *allocated_functions[i].ptr as usize;
|
||||||
let body = fatptr as *const VMFunctionBody as usize;
|
|
||||||
for r in function_relocs {
|
for r in function_relocs {
|
||||||
apply_relocation(body, r, allocated_functions, jt_offsets, allocated_sections);
|
apply_relocation(body, r, allocated_functions, jt_offsets, allocated_sections);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-engine-native"
|
name = "wasmer-engine-native"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer Native Engine"
|
description = "Wasmer Native Engine"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "engine", "native"]
|
keywords = ["wasm", "webassembly", "engine", "native"]
|
||||||
@@ -11,11 +11,11 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
|
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
|
||||||
wasmer-object = { path = "../object", version = "1.0.0-alpha4" }
|
wasmer-object = { path = "../object", version = "1.0.0-alpha5" }
|
||||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
cfg-if = "0.1"
|
cfg-if = "0.1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ impl NativeArtifact {
|
|||||||
) -> Result<Self, CompileError> {
|
) -> Result<Self, CompileError> {
|
||||||
let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
|
let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
|
||||||
PrimaryMap::new();
|
PrimaryMap::new();
|
||||||
for (function_local_index, function_len) in metadata.function_body_lengths.iter() {
|
for (function_local_index, _function_len) in metadata.function_body_lengths.iter() {
|
||||||
let function_name =
|
let function_name =
|
||||||
metadata.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
metadata.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -356,14 +356,9 @@ impl NativeArtifact {
|
|||||||
let func: LibrarySymbol<unsafe extern "C" fn()> = lib
|
let func: LibrarySymbol<unsafe extern "C" fn()> = lib
|
||||||
.get(function_name.as_bytes())
|
.get(function_name.as_bytes())
|
||||||
.map_err(to_compile_error)?;
|
.map_err(to_compile_error)?;
|
||||||
let raw = *func.into_raw();
|
finished_functions.push(FunctionBodyPtr(
|
||||||
// The function pointer is a fat pointer, however this information
|
func.into_raw().into_raw() as *const VMFunctionBody
|
||||||
// is only used when retrieving the trap information which is not yet
|
));
|
||||||
// implemented in this engine.
|
|
||||||
let func_pointer =
|
|
||||||
std::slice::from_raw_parts(raw as *const (), *function_len as usize);
|
|
||||||
let func_pointer = func_pointer as *const [()] as *mut [VMFunctionBody];
|
|
||||||
finished_functions.push(FunctionBodyPtr(func_pointer));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,11 +392,9 @@ impl NativeArtifact {
|
|||||||
let trampoline: LibrarySymbol<unsafe extern "C" fn()> = lib
|
let trampoline: LibrarySymbol<unsafe extern "C" fn()> = lib
|
||||||
.get(function_name.as_bytes())
|
.get(function_name.as_bytes())
|
||||||
.map_err(to_compile_error)?;
|
.map_err(to_compile_error)?;
|
||||||
let raw = *trampoline.into_raw();
|
finished_dynamic_function_trampolines.push(FunctionBodyPtr(
|
||||||
let trampoline_pointer = std::slice::from_raw_parts(raw as *const (), 0);
|
trampoline.into_raw().into_raw() as *const VMFunctionBody,
|
||||||
let trampoline_pointer =
|
));
|
||||||
trampoline_pointer as *const [()] as *mut [VMFunctionBody];
|
|
||||||
finished_dynamic_function_trampolines.push(FunctionBodyPtr(trampoline_pointer));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-engine-object-file"
|
name = "wasmer-engine-object-file"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
description = "Wasmer Object File Engine"
|
description = "Wasmer Object File Engine"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
@@ -11,11 +11,11 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha01.0" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha01.0" }
|
||||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
|
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
|
||||||
wasmer-object = { path = "../object", version = "1.0.0-alpha4" }
|
wasmer-object = { path = "../object", version = "1.0.0-alpha5" }
|
||||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
cfg-if = "0.1"
|
cfg-if = "0.1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -306,12 +306,6 @@ impl ObjectFileArtifact {
|
|||||||
let num_finished_functions = usize::from_ne_bytes(byte_buffer);
|
let num_finished_functions = usize::from_ne_bytes(byte_buffer);
|
||||||
let mut finished_functions = PrimaryMap::new();
|
let mut finished_functions = PrimaryMap::new();
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct SlicePtr {
|
|
||||||
ptr: usize,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
let engine_inner = engine.inner();
|
let engine_inner = engine.inner();
|
||||||
let signature_registry = engine_inner.signatures();
|
let signature_registry = engine_inner.signatures();
|
||||||
let mut sig_map: BTreeMap<SignatureIndex, VMSharedSignatureIndex> = BTreeMap::new();
|
let mut sig_map: BTreeMap<SignatureIndex, VMSharedSignatureIndex> = BTreeMap::new();
|
||||||
@@ -323,14 +317,13 @@ impl ObjectFileArtifact {
|
|||||||
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);
|
||||||
|
|
||||||
let mut sp = SlicePtr { ptr: 0, len: 0 };
|
|
||||||
byte_buffer[0..WORD_SIZE]
|
byte_buffer[0..WORD_SIZE]
|
||||||
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]);
|
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]);
|
||||||
sp.ptr = usize::from_ne_bytes(byte_buffer);
|
let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
|
||||||
cur_offset += WORD_SIZE;
|
cur_offset += WORD_SIZE;
|
||||||
// TODO: we can read back the length here if we serialize it. This will improve debug output.
|
|
||||||
|
|
||||||
let fp = FunctionBodyPtr(mem::transmute(sp));
|
// TODO: we can read back the length here if we serialize it. This will improve debug output.
|
||||||
|
|
||||||
finished_functions.push(fp);
|
finished_functions.push(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,14 +357,12 @@ impl ObjectFileArtifact {
|
|||||||
cur_offset += WORD_SIZE;
|
cur_offset += WORD_SIZE;
|
||||||
let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
|
let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
|
||||||
for _i in 0..num_dynamic_trampoline_functions {
|
for _i in 0..num_dynamic_trampoline_functions {
|
||||||
let mut sp = SlicePtr { ptr: 0, len: 0 };
|
|
||||||
byte_buffer[0..WORD_SIZE]
|
byte_buffer[0..WORD_SIZE]
|
||||||
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]);
|
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]);
|
||||||
sp.ptr = usize::from_ne_bytes(byte_buffer);
|
let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
|
||||||
cur_offset += WORD_SIZE;
|
cur_offset += WORD_SIZE;
|
||||||
|
|
||||||
// TODO: we can read back the length here if we serialize it. This will improve debug output.
|
// TODO: we can read back the length here if we serialize it. This will improve debug output.
|
||||||
let fp = FunctionBodyPtr(mem::transmute(sp));
|
|
||||||
|
|
||||||
finished_dynamic_function_trampolines.push(fp);
|
finished_dynamic_function_trampolines.push(fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-engine"
|
name = "wasmer-engine"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer Engine abstraction"
|
description = "Wasmer Engine abstraction"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly", "engine"]
|
keywords = ["wasm", "webassembly", "engine"]
|
||||||
@@ -11,10 +11,10 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
|
||||||
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
|
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
|
||||||
target-lexicon = { version = "0.10", default-features = false }
|
target-lexicon = { version = "0.11", default-features = false }
|
||||||
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
rustc-demangle = "0.1"
|
rustc-demangle = "0.1"
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ pub fn resolve_imports(
|
|||||||
};
|
};
|
||||||
function_imports.push(VMFunctionImport {
|
function_imports.push(VMFunctionImport {
|
||||||
body: address,
|
body: address,
|
||||||
vmctx: f.vmctx,
|
environment: f.vmctx,
|
||||||
});
|
});
|
||||||
|
|
||||||
host_function_env_initializers.push(f.function_ptr);
|
host_function_env_initializers.push(f.function_ptr);
|
||||||
|
|||||||
@@ -219,6 +219,18 @@ impl Drop for GlobalFrameInfoRegistration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a continuous region of executable memory starting with a function
|
||||||
|
/// entry point.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct FunctionExtent {
|
||||||
|
/// Entry point for normal entry of the function. All addresses in the
|
||||||
|
/// function lie after this address.
|
||||||
|
pub ptr: FunctionBodyPtr,
|
||||||
|
/// Length in bytes.
|
||||||
|
pub length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers a new compiled module's frame information.
|
/// Registers a new compiled module's frame information.
|
||||||
///
|
///
|
||||||
/// This function will register the `names` information for all of the
|
/// This function will register the `names` information for all of the
|
||||||
@@ -227,18 +239,22 @@ impl Drop for GlobalFrameInfoRegistration {
|
|||||||
/// dropped, will be used to unregister all name information from this map.
|
/// dropped, will be used to unregister all name information from this map.
|
||||||
pub fn register(
|
pub fn register(
|
||||||
module: Arc<ModuleInfo>,
|
module: Arc<ModuleInfo>,
|
||||||
finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
|
finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionExtent>,
|
||||||
frame_infos: PrimaryMap<LocalFunctionIndex, SerializableFunctionFrameInfo>,
|
frame_infos: PrimaryMap<LocalFunctionIndex, SerializableFunctionFrameInfo>,
|
||||||
) -> Option<GlobalFrameInfoRegistration> {
|
) -> Option<GlobalFrameInfoRegistration> {
|
||||||
let mut min = usize::max_value();
|
let mut min = usize::max_value();
|
||||||
let mut max = 0;
|
let mut max = 0;
|
||||||
let mut functions = BTreeMap::new();
|
let mut functions = BTreeMap::new();
|
||||||
for (i, allocated) in finished_functions.iter() {
|
for (
|
||||||
let (start, end) = unsafe {
|
i,
|
||||||
let ptr = (***allocated).as_ptr();
|
FunctionExtent {
|
||||||
let len = (***allocated).len();
|
ptr: start,
|
||||||
(ptr as usize, ptr as usize + len)
|
length: len,
|
||||||
};
|
},
|
||||||
|
) in finished_functions.iter()
|
||||||
|
{
|
||||||
|
let start = **start as usize;
|
||||||
|
let end = start + len;
|
||||||
min = cmp::min(min, start);
|
min = cmp::min(min, start);
|
||||||
max = cmp::max(max, end);
|
max = cmp::max(max, end);
|
||||||
let func = FunctionInfo {
|
let func = FunctionInfo {
|
||||||
|
|||||||
@@ -2,5 +2,6 @@ mod error;
|
|||||||
mod frame_info;
|
mod frame_info;
|
||||||
pub use error::RuntimeError;
|
pub use error::RuntimeError;
|
||||||
pub use frame_info::{
|
pub use frame_info::{
|
||||||
register as register_frame_info, FrameInfo, GlobalFrameInfoRegistration, FRAME_INFO,
|
register as register_frame_info, FrameInfo, FunctionExtent, GlobalFrameInfoRegistration,
|
||||||
|
FRAME_INFO,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-object"
|
name = "wasmer-object"
|
||||||
version = "1.0.0-alpha4"
|
version = "1.0.0-alpha5"
|
||||||
description = "Wasmer Native Object generator"
|
description = "Wasmer Native Object generator"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
keywords = ["wasm", "webassembly"]
|
keywords = ["wasm", "webassembly"]
|
||||||
@@ -11,10 +11,10 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
|
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
|
||||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", default-features = false, features = [
|
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", default-features = false, features = [
|
||||||
"std",
|
"std",
|
||||||
"translator"
|
"translator"
|
||||||
] }
|
] }
|
||||||
object = { version = "0.19", default-features = false, features = ["write"] }
|
object = { version = "0.21", default-features = false, features = ["write"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user