Merge branch 'master' into feature/host-env-prototype

This commit is contained in:
Mark McCaskey
2020-11-16 15:13:29 -08:00
committed by GitHub
131 changed files with 7822 additions and 2169 deletions

49
.github/CODEOWNERS vendored
View File

@@ -1,25 +1,24 @@
#
src/ @syrusakbary @MarkMcCaskey
# Backends
lib/compiler-singlepass @losfair @nlewycky
lib/compiler-cranelift @syrusakbary @nlewycky
lib/compiler-llvm @nlewycky @losfair
# Runtime
lib/runtime @syrusakbary @Hywan
lib/c-api @Hywan
# Frontend integrations
## Emscripten
lib/emscripten @MarkMcCaskey @syrusakbary
## WASI
lib/wasi @MarkMcCaskey
# Examples
examples @syrusakbary
# Examples
tests @syrusakbary @MarkMcCaskey
benches @syrusakbary
examples @Hywan @jubianchi
fuzz @syrusakbary
lib/api @syrusakbary @Hywan @MarkMcCaskey
lib/c-api @Hywan @MarkMcCaskey @jubianchi
lib/cache @syrusakbary @Hywan
lib/cli @syrusakbary @MarkMcCaskey
lib/compiler @syrusakbary @nlewycky @losfair @Hywan @MarkMcCaskey
lib/compiler-cranelift @nlewycky @syrusakbary
lib/compiler-llvm @nlewycky @losfair
lib/compiler-singlepass @losfair @nlewycky
lib/deprecated @Hywan @MarkMcCaskey
lib/emscripten @MarkMcCaskey
lib/engine @syrusakbary @MarkMcCaskey @Hywan
lib/engine-jit @syrusakbary @MarkMcCaskey @Hywan
lib/engine-native @syrusakbary @MarkMcCaskey @Hywan
lib/engine-object-file @syrusakbary @MarkMcCaskey @Hywan
lib/object @syrusakbary @nlewycky
lib/vm @syrusakbary @nlewycky @MarkMcCaskey
lib/wasi @MarkMcCaskey
lib/wasi-experimental-io-devices @MarkMcCaskey
lib/wasmer-types @syrusakbary @Hywan
scripts @syrusakbary
tests @MarkMcCaskey

View File

@@ -143,8 +143,8 @@ jobs:
- run: make test
- name: Build and Test C API
run: |
make build-capi
make test-capi
make build-capi
if: matrix.os != 'windows-latest'
- name: Build C API on Windows
run: make build-capi

View File

@@ -7,9 +7,21 @@
## **[Unreleased]**
- [#1710](https://github.com/wasmerio/wasmer/pull/1710) Memory for function call trampolines is now owned by the Artifact.
### 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.
- [#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.
@@ -20,15 +32,26 @@
- [#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.
- [#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
- [#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.
- [#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
- [#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
@@ -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.
- [#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.
- [#1624](https://github.com/wasmerio/wasmer/pull/1624) Add Value::I32/Value::I64 converters from unsigned ints.
### Changed
- [#1682](https://github.com/wasmerio/wasmer/pull/1682) Improve error reporting when making a memory with invalid settings.

671
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-workspace"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer workspace"
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
@@ -10,20 +10,20 @@ publish = false
autoexamples = false
[dependencies]
wasmer = { version = "1.0.0-alpha4", path = "lib/api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha4", path = "lib/compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha4", path = "lib/compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha4", path = "lib/compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha4", path = "lib/compiler-llvm", optional = true }
wasmer-engine = { version = "1.0.0-alpha4", path = "lib/engine" }
wasmer-engine-jit = { version = "1.0.0-alpha4", path = "lib/engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha4", path = "lib/engine-native", optional = true }
wasmer-engine-object-file = { version = "1.0.0-alpha4", path = "lib/engine-object-file", optional = true }
wasmer-wasi = { version = "1.0.0-alpha4", path = "lib/wasi", optional = true }
wasmer-wast = { version = "1.0.0-alpha4", path = "tests/lib/wast", optional = true }
wasmer-cache = { version = "1.0.0-alpha4", path = "lib/cache", optional = true }
wasmer-types = { version = "1.0.0-alpha4", path = "lib/wasmer-types" }
cfg-if = "0.1"
wasmer = { version = "1.0.0-alpha5", path = "lib/api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha5", path = "lib/compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "lib/compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "lib/compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "lib/compiler-llvm", optional = true }
wasmer-engine = { version = "1.0.0-alpha5", path = "lib/engine" }
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "lib/engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha5", path = "lib/engine-native", optional = true }
wasmer-engine-object-file = { version = "1.0.0-alpha5", path = "lib/engine-object-file", optional = true }
wasmer-wasi = { version = "1.0.0-alpha5", path = "lib/wasi", optional = true }
wasmer-wast = { version = "1.0.0-alpha5", path = "tests/lib/wast", optional = true }
wasmer-cache = { version = "1.0.0-alpha5", path = "lib/cache", optional = true }
wasmer-types = { version = "1.0.0-alpha5", path = "lib/wasmer-types" }
cfg-if = "1.0"
[workspace]
members = [
@@ -58,7 +58,7 @@ test-generator = { path = "tests/lib/test-generator" }
build-deps = "0.1.4"
anyhow = "1.0"
glob = "0.3"
rustc_version = "0.2"
rustc_version = "0.3"
[dev-dependencies]
anyhow = "1.0"
@@ -212,6 +212,11 @@ name = "imported-global"
path = "examples/imports_global.rs"
required-features = ["cranelift"]
[[example]]
name = "tunables-limit-memory"
path = "examples/tunables_limit_memory.rs"
required-features = ["cranelift"]
[[example]]
name = "wasi"
path = "examples/wasi.rs"
@@ -226,3 +231,18 @@ required-features = ["cranelift"]
name = "memory"
path = "examples/memory.rs"
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"]

View File

@@ -61,11 +61,13 @@ ifneq ($(OS), Windows_NT)
endif
$(info Available compilers: $(bold)$(green)${compilers}$(reset))
compiler_features_spaced := $(foreach compiler,$(compilers),$(compiler))
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 #
@@ -89,20 +91,41 @@ build-docs:
cargo doc --release $(compiler_features) --document-private-items --no-deps --workspace
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
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:
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:
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:
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 \
--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 \
--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:
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:
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 #
@@ -163,6 +194,8 @@ test-packages:
# 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.
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
cargo test --manifest-path lib/c-api/Cargo.toml --release \
--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 \
--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:
cargo test --manifest-path lib/wasi/Cargo.toml --release

View File

@@ -134,7 +134,7 @@ qjs >
[js logo]: ./assets/languages/js.svg
[js integration]: https://github.com/wasmerio/wasmer-js
[`@wasmerio` npm packages]: https://www.npmjs.com/org/wasmer
[js docs]: https://docs.wasmer.io/wasmer-js/wasmer-js
[js docs]: https://docs.wasmer.io/integrations/js/reference-api
[ruby logo]: ./assets/languages/ruby.svg
[ruby integration]: https://github.com/wasmerio/wasmer-ruby

74
docs/deps_dedup.dot Normal file
View 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
View 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&#45;engine&#45;jit</text>
</g>
<!-- n0&#45;&gt;n6 -->
<g id="edge12" class="edge">
<title>n0&#45;&gt;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&#45;engine&#45;native</text>
</g>
<!-- n0&#45;&gt;n7 -->
<g id="edge13" class="edge">
<title>n0&#45;&gt;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&#45;compiler&#45;cranelift</text>
</g>
<!-- n0&#45;&gt;n2 -->
<g id="edge9" class="edge">
<title>n0&#45;&gt;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&#45;compiler&#45;llvm</text>
</g>
<!-- n0&#45;&gt;n3 -->
<g id="edge10" class="edge">
<title>n0&#45;&gt;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&#45;compiler&#45;singlepass</text>
</g>
<!-- n0&#45;&gt;n4 -->
<g id="edge11" class="edge">
<title>n0&#45;&gt;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&#45;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&#45;vm</text>
</g>
<!-- n1&#45;&gt;n9 -->
<g id="edge20" class="edge">
<title>n1&#45;&gt;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&#45;engine</text>
</g>
<!-- n5&#45;&gt;n1 -->
<g id="edge19" class="edge">
<title>n5&#45;&gt;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&#45;&gt;n5 -->
<g id="edge17" class="edge">
<title>n6&#45;&gt;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&#45;&gt;n5 -->
<g id="edge18" class="edge">
<title>n7&#45;&gt;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&#45;types</text>
</g>
<!-- n9&#45;&gt;n8 -->
<g id="edge21" class="edge">
<title>n9&#45;&gt;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&#45;c&#45;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&#45;emscripten</text>
</g>
<!-- n10&#45;&gt;n11 -->
<g id="edge5" class="edge">
<title>n10&#45;&gt;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&#45;wasi</text>
</g>
<!-- n10&#45;&gt;n12 -->
<g id="edge6" class="edge">
<title>n10&#45;&gt;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&#45;&gt;n0 -->
<g id="edge7" class="edge">
<title>n11&#45;&gt;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&#45;&gt;n0 -->
<g id="edge8" class="edge">
<title>n12&#45;&gt;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&#45;cache</text>
</g>
<!-- n13&#45;&gt;n0 -->
<g id="edge4" class="edge">
<title>n13&#45;&gt;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&#45;cli</text>
</g>
<!-- n14&#45;&gt;n11 -->
<g id="edge3" class="edge">
<title>n14&#45;&gt;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&#45;&gt;n12 -->
<g id="edge2" class="edge">
<title>n14&#45;&gt;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&#45;&gt;n13 -->
<g id="edge1" class="edge">
<title>n14&#45;&gt;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&#45;&gt;n1 -->
<g id="edge14" class="edge">
<title>n2&#45;&gt;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&#45;&gt;n1 -->
<g id="edge15" class="edge">
<title>n3&#45;&gt;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&#45;&gt;n1 -->
<g id="edge16" class="edge">
<title>n4&#45;&gt;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
View 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
![Wasmer dependencies graph](./deps_dedup.svg)
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

View File

@@ -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
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
1. [**JIT engine**][engine-jit], explains what an engine is, what the
@@ -107,7 +274,7 @@ example.
### Compilers
5. [**Singlepass compiler**][compiler-singlepass], explains how to use
1. [**Singlepass compiler**][compiler-singlepass], explains how to use
the [`wasmer-compiler-singlepass`] compiler.
_Keywords_: compiler, singlepass.
@@ -121,7 +288,7 @@ example.
</details>
6. [**Cranelift compiler**][compiler-cranelift], explains how to use
2. [**Cranelift compiler**][compiler-cranelift], explains how to use
the [`wasmer-compiler-cranelift`] compiler.
_Keywords_: compiler, cranelift.
@@ -135,7 +302,7 @@ example.
</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.
_Keywords_: compiler, llvm.
@@ -149,116 +316,9 @@ example.
</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
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.
_Keywords_: wasi, system, interface
@@ -284,6 +344,7 @@ example.
[exported-memory]: ./exports_memory.rs
[imported-global]: ./imports_global.rs
[imported-function]: ./imports_function.rs
[instance]: ./instance.rs
[wasi]: ./wasi.rs
[table]: ./table.rs
[memory]: ./memory.rs

View File

@@ -1,5 +1,18 @@
//! This example shows how the host can terminate execution of Wasm early from
//! inside a host function called by the Wasm.
//! There are cases where you may want to interrupt this synchronous execution of the WASM module
//! 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 std::fmt;
@@ -21,12 +34,6 @@ impl fmt::Display for ExitCode {
// And then we implement `std::error::Error`.
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<()> {
// Let's declare the Wasm module with the text representation.
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());
println!("Compiling module...");
// Let's compile the Wasm module.
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! {
"env" => {
"early_exit" => Function::new_native(&store, early_exit),
}
};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
// Here we go.
//
// Get the `run` function which we'll use as our entrypoint.
let run_func: NativeFunc<(i32, i32), i32> =
instance.exports.get_native_function("run").unwrap();
println!("Calling `run` function...");
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) {
Ok(result) => {
bail!(
@@ -66,12 +92,13 @@ fn main() -> anyhow::Result<()> {
result
);
}
// We're expecting it to fail.
// We attempt to downcast the error into the error type that we were expecting.
// In case of a failure, which we expect, we attempt to downcast the error into the error
// type that we were expecting.
Err(e) => match e.downcast::<ExitCode>() {
// We found the exit code used to terminate execution.
Ok(exit_code) => {
println!("Exited early with exit code: {}", exit_code);
Ok(())
}
Err(e) => {

103
examples/errors.rs Normal file
View 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()
}

View File

@@ -72,10 +72,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// 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);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
println!("Results: {:?}", result);
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'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
// those values don't match the exported function signature, an
// error will be raised.
let sum = sum.native::<(i32, i32), i32>()?;
let sum_native = sum.native::<(i32, i32), i32>()?;
println!("Calling `sum` function (natively)...");
// Let's call the `sum` exported function. The parameters are
// statically typed Rust values of type `i32` and `i32`. The
// 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);
assert_eq!(result, 3);
assert_eq!(result, 7);
// Much nicer, isn't it?
//

View File

@@ -68,16 +68,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let one = instance.exports.get_global("one")?;
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 one_type = one.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.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.ty, Type::F32);
@@ -93,14 +93,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.get_function("get_one")?
.native::<(), f32>()?;
let one_result = get_one.call()?;
let some_result = some.get();
let one_value = get_one.call()?;
let some_value = some.get();
println!("one value: {:?}", one_result);
assert_eq!(one_result, 1.0);
println!("`one` value: {:?}", one_value);
assert_eq!(one_value, 1.0);
println!("some value: {:?}", some_result);
assert_eq!(some_result, Value::F32(0.0));
println!("`some` value: {:?}", some_value);
assert_eq!(some_value, Value::F32(0.0));
println!("Setting global values...");
// 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();
println!("one value after `set`: {:?}", one_result);
println!("`one` value after `set`: {:?}", one_result);
assert_eq!(one_result, Value::F32(1.0));
// 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, ()>()?;
set_some.call(21.0)?;
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));
some.set(Value::F32(42.0))?;
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));
Ok(())

View File

@@ -70,7 +70,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
let multiply_native = Function::new_native(&store, multiply);
// Create an empty import object.
// Create an import object.
let import_object = imports! {
"env" => {
"multiply_dynamic" => multiply_dynamic,

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

View File

@@ -1,7 +1,21 @@
use wasmer::{
imports, wat2wasm, Extern, Function, Instance, Memory, MemoryType, Module, NativeFunc, Pages,
Store, Table, TableType, Type, Value,
};
//! With Wasmer you'll be able to interact with guest module memory.
//!
//! 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_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
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(
r#"
(module
@@ -35,47 +53,87 @@ fn main() -> anyhow::Result<()> {
.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());
// Then compile our Wasm.
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! {};
// And instantiate it with no imports.
println!("Instantiating module...");
// Let's instantiate the Wasm module.
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 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 memory = instance.exports.get_memory("memory")?;
let mem_addr = 0x2220;
let val = 0xFEFEFFE;
// We now have an instance ready to be used.
//
// 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().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)?;
assert_eq!(memory.size(), Pages::from(3));
let result = mem_size.call()?;
assert_eq!(result, 3);
assert_eq!(memory.data_size(), 65536 * 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)?;
// -------------
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)?;
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);
// -------------
Ok(())
}

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

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "High-performant WebAssembly runtime"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "runtime", "vm"]
@@ -11,29 +11,29 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0-alpha4", optional = true }
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "1.0.0-alpha4", optional = true }
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "1.0.0-alpha4", optional = true }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
wasmer-derive = { path = "../derive", version = "1.0.0-alpha4" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha4", optional = true }
wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha4", optional = true }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0-alpha5", 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-alpha5", optional = true }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
wasmer-derive = { path = "../derive", version = "1.0.0-alpha5" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha5", optional = true }
wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha5", optional = true }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
indexmap = { version = "1.4", features = ["serde-1"] }
cfg-if = "0.1"
wat = { version = "1.0", optional = true }
thiserror = "1.0"
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]
winapi = "0.3"
[dev-dependencies]
# for the binary wasmer.rs
libc = { version = "^0.2.69", default-features = false }
libc = { version = "^0.2", default-features = false }
wat = "1.0"
tempfile = "3.1"
anyhow = "1.0"

View File

@@ -12,8 +12,8 @@ use std::cmp::max;
use std::fmt;
use wasmer_vm::{
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction,
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
VMTrampoline,
VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment,
VMFunctionKind, VMTrampoline,
};
/// 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
// generated dynamic trampoline.
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 {
store: store.clone(),
@@ -138,7 +140,9 @@ impl Function {
// The engine linker will replace the address with one pointing to a
// generated dynamic trampoline.
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
let function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish)
@@ -184,7 +188,9 @@ impl Function {
{
let function = inner::Function::<Args, Rets>::new(func);
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();
Self {
@@ -242,7 +248,9 @@ impl Function {
// In the case of Host-defined functions `VMContext` is whatever environment
// the user want to attach to the function.
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
let function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish)

View File

@@ -87,21 +87,26 @@ impl Memory {
&self.store
}
/// TODO: document this function.
/// Retrieve a slice of the memory contents.
///
/// # 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] {
self.data_unchecked_mut()
}
/// TODO: document this function, it's trivial to cause UB/break soundness with this
/// method.
/// Retrieve a mutable slice of the memory contents.
///
/// # 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)]
pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
let definition = self.memory.vmmemory();

View File

@@ -83,7 +83,17 @@ pub use wasmer_types::{
Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
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 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")]
pub use wat::parse_bytes as wat2wasm;

View File

@@ -17,7 +17,7 @@ use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, W
use std::panic::{catch_unwind, AssertUnwindSafe};
use wasmer_types::NativeWasmType;
use wasmer_vm::{
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
ExportFunction, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind,
};
/// A WebAssembly function that can be called natively
@@ -26,7 +26,7 @@ pub struct NativeFunc<Args = (), Rets = ()> {
definition: FunctionDefinition,
store: Store,
address: *const VMFunctionBody,
vmctx: *mut VMContext,
vmctx: VMFunctionEnvironment,
arg_kind: VMFunctionKind,
// exported: ExportFunction,
_phantom: PhantomData<(Args, Rets)>,
@@ -42,7 +42,7 @@ where
pub(crate) fn new(
store: Store,
address: *const VMFunctionBody,
vmctx: *mut VMContext,
vmctx: VMFunctionEnvironment,
arg_kind: VMFunctionKind,
definition: FunctionDefinition,
) -> Self {
@@ -169,7 +169,7 @@ macro_rules! impl_native_traits {
match self.arg_kind {
VMFunctionKind::Static => {
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
f( self.vmctx, $( $x, )* )
})).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 results = if !has_env {
type VMContextWithoutEnv = VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv>;
let ctx = self.vmctx as *mut VMContextWithoutEnv;
unsafe { (*ctx).ctx.call(&params_list)? }
unsafe {
let ctx = self.vmctx.host_env as *mut VMContextWithoutEnv;
(*ctx).ctx.call(&params_list)?
}
} else {
type VMContextWithEnv = VMDynamicFunctionContext<VMDynamicFunctionWithEnv<std::ffi::c_void>>;
let ctx = self.vmctx as *mut VMContextWithEnv;
unsafe { (*ctx).ctx.call(&params_list)? }
unsafe {
let ctx = self.vmctx.host_env as *mut VMContextWithEnv;
(*ctx).ctx.call(&params_list)?
}
};
let mut rets_list_array = Rets::empty_array();
let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128;

View File

@@ -71,6 +71,7 @@ impl BaseTunables for Tunables {
let maximum = memory.maximum.unwrap_or_else(Pages::max_value);
if maximum <= self.static_memory_bound {
MemoryStyle::Static {
// Bound can be larger than the maximum for performance reasons
bound: self.static_memory_bound,
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),
}
}
}

View File

@@ -56,7 +56,9 @@ impl ValFuncRef for Val {
Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc {
func_ptr: ptr::null(),
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(),
_ => return Err(RuntimeError::new("val is not funcref")),

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-c-api"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer C API library"
categories = ["wasm", "api-bindings"]
keywords = ["wasm", "webassembly", "runtime"]
@@ -15,21 +15,21 @@ edition = "2018"
crate-type = ["cdylib", "rlib", "staticlib"]
[dependencies]
wasmer = { version = "1.0.0-alpha4", path = "../api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha4", path = "../compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha4", path = "../compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha4", path = "../compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha4", path = "../compiler-llvm", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha4", path = "../emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha4", path = "../engine" }
wasmer-engine-jit = { version = "1.0.0-alpha4", path = "../engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha4", path = "../engine-native", optional = true }
wasmer-engine-object-file = { version = "1.0.0-alpha4", path = "../engine-object-file", optional = true }
wasmer-wasi = { version = "1.0.0-alpha4", path = "../wasi", optional = true }
wasmer-types = { version = "1.0.0-alpha4", path = "../wasmer-types" }
cfg-if = "0.1"
wasmer = { version = "1.0.0-alpha5", path = "../api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha5", path = "../compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "../compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "../compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "../compiler-llvm", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha5", path = "../emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha5", path = "../engine" }
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "../engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha5", path = "../engine-native", optional = true }
wasmer-engine-object-file = { version = "1.0.0-alpha5", path = "../engine-object-file", optional = true }
wasmer-wasi = { version = "1.0.0-alpha5", path = "../wasi", optional = true }
wasmer-types = { version = "1.0.0-alpha5", path = "../wasmer-types" }
cfg-if = "1.0"
lazy_static = "1"
libc = { version = "^0.2.69", default-features = false }
libc = { version = "^0.2", default-features = false }
libffi = { version = "0.9" }
serde = { version = "1", optional = true, features = ["derive"] }
thiserror = "1"
@@ -37,7 +37,10 @@ typetag = { version = "0.1", optional = true }
paste = "0.1"
# for generating code in the same way thot the wasm-c-api does
# Commented out for now until we can find a solution to the exported function problem
# wasmer-wasm-c-api = { version = "1.0.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]
default = [
@@ -89,4 +92,4 @@ cranelift-backend = ["cranelift"]
llvm-backend = ["llvm"]
[build-dependencies]
cbindgen = "0.15"
cbindgen = "0.15"

View File

@@ -61,6 +61,7 @@ fn main() {
build_wasm_c_api_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.
@@ -389,3 +390,44 @@ fn exclude_items_from_wasm_c_api(builder: Builder) -> Builder {
.exclude_item("wasmer_engine_t")
.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

View File

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

View File

@@ -1,3 +1,4 @@
use crate::error::{update_last_error, CApiError};
use cfg_if::cfg_if;
use std::sync::Arc;
use wasmer::Engine;
@@ -8,7 +9,10 @@ use wasmer_engine_native::Native;
#[cfg(feature = "object-file")]
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)]
#[repr(C)]
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)]
#[repr(C)]
#[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
/// this can be a wasmer-specific type with wasmer-specific functions for manipulating it
#[derive(Debug, Default)]
#[repr(C)]
pub struct wasm_config_t {
@@ -67,12 +76,15 @@ pub struct wasm_config_t {
engine: wasmer_engine_t,
}
/// Create a new Wasmer configuration.
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_config_new() -> Box<wasm_config_t> {
Box::new(wasm_config_t::default())
}
/// Configure the compiler to use.
#[no_mangle]
pub extern "C" fn wasm_config_set_compiler(
config: &mut wasm_config_t,
@@ -81,13 +93,17 @@ pub extern "C" fn wasm_config_set_compiler(
config.compiler = compiler;
}
/// Configure the engine to use.
#[no_mangle]
pub extern "C" fn wasm_config_set_engine(config: &mut wasm_config_t, engine: wasmer_engine_t) {
config.engine = engine;
}
/// An engine is used by the store to drive the compilation and the
/// execution of a WebAssembly module.
///
/// cbindgen:ignore
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct wasm_engine_t {
pub(crate) inner: Arc<dyn Engine + Send + Sync>,
}
@@ -112,6 +128,7 @@ fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
cfg_if! {
if #[cfg(all(feature = "jit", feature = "compiler"))] {
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
@@ -121,6 +138,7 @@ cfg_if! {
}
else if #[cfg(feature = "jit")] {
// Headless JIT
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
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"))] {
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let mut compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
@@ -136,6 +155,7 @@ cfg_if! {
}
}
else if #[cfg(feature = "native")] {
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
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.
// So if we get here, we default to headless mode regardless of if `compiler` is enabled.
else if #[cfg(feature = "object-file")] {
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let engine: Arc<dyn Engine + Send + Sync> = Arc::new(ObjectFile::headless().engine());
@@ -152,6 +173,7 @@ cfg_if! {
}
}
else {
/// cbindgen:ignore
#[no_mangle]
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`");
@@ -161,14 +183,24 @@ cfg_if! {
/// cbindgen:ignore
#[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
#[no_mangle]
pub extern "C" fn wasm_engine_new_with_config(
config: Box<wasm_config_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! {
if #[cfg(feature = "compiler")] {
#[allow(unused_mut)]
@@ -178,7 +210,7 @@ pub extern "C" fn wasm_engine_new_with_config(
if #[cfg(feature = "cranelift")] {
Box::new(wasmer_compiler_cranelift::Cranelift::default())
} 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")] {
Box::new(wasmer_compiler_llvm::LLVM::default())
} 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")] {
Box::new(wasmer_compiler_singlepass::Singlepass::default())
} 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")] {
Arc::new(JIT::new(&*compiler_config).engine())
} 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")] {
Arc::new(Native::new(&mut *compiler_config).engine())
} 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")] {
Arc::new(ObjectFile::headless().engine())
} 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")] {
Arc::new(JIT::headless().engine())
} 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")] {
Arc::new(Native::headless().engine())
} 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")] {
Arc::new(ObjectFile::headless().engine())
} else {
return None;
return return_with_error("Wasmer has not been compiled with the `object-file` feature.");
}
}
},

View File

@@ -7,6 +7,7 @@ use std::ffi::c_void;
use std::sync::Arc;
use wasmer::{Function, Instance, RuntimeError, Val};
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct wasm_func_t {
pub(crate) inner: Function,
@@ -32,12 +33,15 @@ pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
#[no_mangle]
pub unsafe extern "C" fn wasm_func_new(
store: &wasm_store_t,
ft: &wasm_functype_t,
callback: wasm_func_callback_t,
store: Option<&wasm_store_t>,
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_t>,
) -> Option<Box<wasm_func_t>> {
// TODO: handle null pointers?
let func_sig = ft.sig();
let store = store?;
let function_type = function_type?;
let callback = callback?;
let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args: wasm_val_vec_t = args
@@ -84,14 +88,17 @@ pub unsafe extern "C" fn wasm_func_new(
#[no_mangle]
pub unsafe extern "C" fn wasm_func_new_with_env(
store: &wasm_store_t,
ft: &wasm_functype_t,
callback: wasm_func_callback_with_env_t,
store: Option<&wasm_store_t>,
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_with_env_t>,
env: *mut c_void,
finalizer: wasm_env_finalizer_t,
) -> Option<Box<wasm_func_t>> {
// TODO: handle null pointers?
let func_sig = ft.sig();
let store = store?;
let function_type = function_type?;
let callback = callback?;
let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();
#[repr(transparent)]
@@ -154,10 +161,13 @@ pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
#[no_mangle]
pub unsafe extern "C" fn wasm_func_call(
func: &wasm_func_t,
args: &wasm_val_vec_t,
func: Option<&wasm_func_t>,
args: Option<&wasm_val_vec_t>,
results: &mut wasm_val_vec_t,
) -> Option<Box<wasm_trap_t>> {
let func = func?;
let args = args?;
let params = args
.into_slice()
.map(|slice| {
@@ -165,18 +175,34 @@ pub unsafe extern "C" fn wasm_func_call(
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.expect("Argument conversion failed")
.expect("Arguments conversion failed")
})
.unwrap_or_default();
match func.inner.call(&params) {
Ok(wasm_results) => {
*results = wasm_results
let vals = wasm_results
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed")
.into();
.expect("Results conversion failed");
// `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
}
@@ -195,6 +221,8 @@ pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
}
#[no_mangle]
pub extern "C" fn wasm_func_type(func: &wasm_func_t) -> Box<wasm_functype_t> {
Box::new(wasm_functype_t::new(func.inner.ty().clone()))
pub extern "C" fn wasm_func_type(func: Option<&wasm_func_t>) -> Option<Box<wasm_functype_t>> {
let func = func?;
Some(Box::new(wasm_functype_t::new(func.inner.ty().clone())))
}

View File

@@ -1,6 +1,7 @@
use super::super::store::wasm_store_t;
use super::super::types::wasm_globaltype_t;
use super::super::value::wasm_val_t;
use crate::error::update_last_error;
use std::convert::TryInto;
use wasmer::{Global, Val};
@@ -12,14 +13,18 @@ pub struct wasm_global_t {
#[no_mangle]
pub unsafe extern "C" fn wasm_global_new(
store: &wasm_store_t,
gt: &wasm_globaltype_t,
val: &wasm_val_t,
store: Option<&wasm_store_t>,
global_type: Option<&wasm_globaltype_t>,
val: Option<&wasm_val_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 store = &store.inner;
let global = if gt.mutability.is_mutable() {
let global = if global_type.mutability.is_mutable() {
Global::new_mut(store, wasm_val)
} else {
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
#[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
Box::new(wasm_global_t {
inner: wasm_global.inner.clone(),
inner: global.inner.clone(),
})
}
#[no_mangle]
pub unsafe extern "C" fn wasm_global_get(wasm_global: &wasm_global_t, out: &mut wasm_val_t) {
let value = wasm_global.inner.get();
pub unsafe extern "C" fn wasm_global_get(
global: &wasm_global_t,
// own
out: &mut wasm_val_t,
) {
let value = global.inner.get();
*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]
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();
wasm_global.inner.set(value);
if let Err(e) = global.inner.set(value) {
update_last_error(e);
}
}
#[no_mangle]
@@ -61,6 +75,6 @@ pub unsafe extern "C" fn wasm_global_same(
}
#[no_mangle]
pub extern "C" fn wasm_global_type(wasm_global: &wasm_global_t) -> Box<wasm_globaltype_t> {
Box::new(wasm_globaltype_t::new(wasm_global.inner.ty().clone()))
pub extern "C" fn wasm_global_type(global: &wasm_global_t) -> Box<wasm_globaltype_t> {
Box::new(wasm_globaltype_t::new(global.inner.ty().clone()))
}

View File

@@ -11,11 +11,14 @@ pub struct wasm_memory_t {
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_new(
store: &wasm_store_t,
mt: &wasm_memorytype_t,
store: Option<&wasm_store_t>,
memory_type: Option<&wasm_memorytype_t>,
) -> Option<Box<wasm_memory_t>> {
let md = mt.as_memorytype().clone();
let memory = c_try!(Memory::new(&store.inner, md));
let store = store?;
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 }))
}
@@ -33,8 +36,12 @@ pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_me
}
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_type(memory: &wasm_memory_t) -> Box<wasm_memorytype_t> {
Box::new(wasm_memorytype_t::new(memory.inner.ty().clone()))
pub unsafe extern "C" fn wasm_memory_type(
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

View File

@@ -6,7 +6,6 @@ mod table;
pub use function::*;
pub use global::*;
pub use memory::*;
use std::ptr::NonNull;
use std::sync::Arc;
pub use table::*;
use wasmer::{Extern, Instance};
@@ -22,10 +21,9 @@ wasm_declare_boxed_vec!(extern);
#[no_mangle]
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>> {
let func_ptr = func_ptr?;
let func = func_ptr.as_ref();
let func = func?;
Some(Box::new(wasm_extern_t {
instance: func.instance.clone(),
@@ -35,13 +33,12 @@ pub unsafe extern "C" fn wasm_func_as_extern(
#[no_mangle]
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>> {
let global_ptr = global_ptr?;
let global = global_ptr.as_ref();
let global = global?;
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,
inner: Extern::Global(global.inner.clone()),
}))
@@ -49,13 +46,12 @@ pub unsafe extern "C" fn wasm_global_as_extern(
#[no_mangle]
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>> {
let memory_ptr = memory_ptr?;
let memory = memory_ptr.as_ref();
let memory = memory?;
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,
inner: Extern::Memory(memory.inner.clone()),
}))
@@ -63,13 +59,12 @@ pub unsafe extern "C" fn wasm_memory_as_extern(
#[no_mangle]
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>> {
let table_ptr = table_ptr?;
let table = table_ptr.as_ref();
let table = table?;
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,
inner: Extern::Table(table.inner.clone()),
}))
@@ -77,10 +72,10 @@ pub unsafe extern "C" fn wasm_table_as_extern(
#[no_mangle]
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>> {
let extern_ptr = extern_ptr?;
let r#extern = extern_ptr.as_ref();
let r#extern = r#extern?;
if let Extern::Function(f) = &r#extern.inner {
Some(Box::new(wasm_func_t {
inner: f.clone(),
@@ -93,10 +88,10 @@ pub unsafe extern "C" fn wasm_extern_as_func(
#[no_mangle]
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>> {
let extern_ptr = extern_ptr?;
let r#extern = extern_ptr.as_ref();
let r#extern = r#extern?;
if let Extern::Global(g) = &r#extern.inner {
Some(Box::new(wasm_global_t { inner: g.clone() }))
} else {
@@ -106,10 +101,10 @@ pub unsafe extern "C" fn wasm_extern_as_global(
#[no_mangle]
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>> {
let extern_ptr = extern_ptr?;
let r#extern = extern_ptr.as_ref();
let r#extern = r#extern?;
if let Extern::Memory(m) = &r#extern.inner {
Some(Box::new(wasm_memory_t { inner: m.clone() }))
} else {
@@ -119,10 +114,10 @@ pub unsafe extern "C" fn wasm_extern_as_memory(
#[no_mangle]
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>> {
let extern_ptr = extern_ptr?;
let r#extern = extern_ptr.as_ref();
let r#extern = r#extern?;
if let Extern::Table(t) = &r#extern.inner {
Some(Box::new(wasm_table_t { inner: t.clone() }))
} else {

View File

@@ -10,44 +10,46 @@ pub struct wasm_table_t {
#[no_mangle]
pub unsafe extern "C" fn wasm_table_new(
store: &wasm_store_t,
tt: &wasm_tabletype_t,
store: Option<&wasm_store_t>,
table_type: Option<&wasm_tabletype_t>,
init: *const wasm_ref_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 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 }))
*/
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_delete(_table: Option<Box<wasm_table_t>>) {}
#[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
Box::new(wasm_table_t {
inner: wasm_table.inner.clone(),
inner: table.inner.clone(),
})
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_same(
wasm_table1: &wasm_table_t,
wasm_table2: &wasm_table_t,
) -> bool {
wasm_table1.inner.same(&wasm_table2.inner)
pub unsafe extern "C" fn wasm_table_same(table1: &wasm_table_t, table2: &wasm_table_t) -> bool {
table1.inner.same(&table2.inner)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_size(wasm_table: &wasm_table_t) -> usize {
wasm_table.inner.size() as _
pub unsafe extern "C" fn wasm_table_size(table: &wasm_table_t) -> usize {
table.inner.size() as _
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_grow(
_wasm_table: &mut wasm_table_t,
_table: &mut wasm_table_t,
_delta: wasm_table_size_t,
_init: *mut wasm_ref_t,
) -> bool {

View File

@@ -5,7 +5,7 @@ use super::trap::wasm_trap_t;
use crate::ordered_resolver::OrderedResolver;
use std::mem;
use std::sync::Arc;
use wasmer::{Extern, Instance};
use wasmer::{Extern, Instance, InstantiationError};
#[allow(non_camel_case_types)]
pub struct wasm_instance_t {
@@ -14,12 +14,14 @@ pub struct wasm_instance_t {
#[no_mangle]
pub unsafe extern "C" fn wasm_instance_new(
_store: &wasm_store_t,
module: &wasm_module_t,
imports: &wasm_extern_vec_t,
// own
_traps: *mut *mut wasm_trap_t,
_store: Option<&wasm_store_t>,
module: Option<&wasm_module_t>,
imports: Option<&wasm_extern_vec_t>,
traps: *mut *mut wasm_trap_t,
) -> Option<Box<wasm_instance_t>> {
let module = module?;
let imports = imports?;
let wasm_module = &module.inner;
let module_imports = wasm_module.imports();
let module_import_count = module_imports.len();
@@ -32,7 +34,23 @@ pub unsafe extern "C" fn wasm_instance_new(
.cloned()
.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 }))
}
@@ -42,7 +60,7 @@ pub unsafe extern "C" fn wasm_instance_delete(_instance: Option<Box<wasm_instanc
#[no_mangle]
pub unsafe extern "C" fn wasm_instance_exports(
instance: &wasm_instance_t,
// TODO: review types on wasm_declare_vec, handle the optional pointer part properly
// own
out: &mut wasm_extern_vec_t,
) {
let instance = &instance.inner;
@@ -55,6 +73,7 @@ pub unsafe extern "C" fn wasm_instance_exports(
} else {
None
};
Box::into_raw(Box::new(wasm_extern_t {
instance: Some(Arc::clone(instance)),
inner: r#extern.clone(),
@@ -65,6 +84,6 @@ pub unsafe extern "C" fn wasm_instance_exports(
out.size = extern_vec.len();
out.data = extern_vec.as_mut_ptr();
// TODO: double check that the destructor will work correctly here
mem::forget(extern_vec);
}

View File

@@ -17,6 +17,7 @@ macro_rules! wasm_declare_vec_inner {
macro_rules! wasm_declare_vec {
($name:ident) => {
paste::item! {
#[derive(Debug)]
#[repr(C)]
pub struct [<wasm_ $name _vec_t>] {
pub size: usize,
@@ -56,12 +57,24 @@ macro_rules! wasm_declare_vec {
impl [<wasm_ $name _vec_t>] {
pub unsafe fn into_slice(&self) -> Option<&[[<wasm_ $name _t>]]>{
if self.data.is_null() {
if self.is_uninitialized() {
return None;
}
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)
@@ -108,6 +121,7 @@ macro_rules! wasm_declare_vec {
macro_rules! wasm_declare_boxed_vec {
($name:ident) => {
paste::item! {
#[derive(Debug)]
#[repr(C)]
pub struct [<wasm_ $name _vec_t>] {
pub size: usize,
@@ -170,7 +184,7 @@ macro_rules! wasm_declare_boxed_vec {
let vec = &mut *ptr;
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<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.size = 0;
}

View File

@@ -3,9 +3,8 @@ use super::types::{
wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t,
wasm_importtype_vec_t,
};
use crate::error::update_last_error;
use crate::error::{update_last_error, CApiError};
use std::ptr::NonNull;
use std::slice;
use std::sync::Arc;
use wasmer::Module;
@@ -14,14 +13,58 @@ pub struct wasm_module_t {
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]
pub unsafe extern "C" fn wasm_module_new(
store: &wasm_store_t,
bytes: &wasm_byte_vec_t,
store: Option<&wasm_store_t>,
bytes: Option<&wasm_byte_vec_t>,
) -> Option<Box<wasm_module_t>> {
// TODO: review lifetime of byte slice
let wasm_byte_slice: &[u8] = slice::from_raw_parts_mut(bytes.data, bytes.size);
let module = c_try!(Module::from_binary(&store.inner, wasm_byte_slice));
let store = store?;
let bytes = bytes?;
let bytes = bytes.into_slice()?;
let module = c_try!(Module::from_binary(&store.inner, bytes));
Some(Box::new(wasm_module_t {
inner: Arc::new(module),
@@ -33,13 +76,24 @@ pub unsafe extern "C" fn wasm_module_delete(_module: Option<Box<wasm_module_t>>)
#[no_mangle]
pub unsafe extern "C" fn wasm_module_validate(
store: &wasm_store_t,
bytes: &wasm_byte_vec_t,
store: Option<&wasm_store_t>,
bytes: Option<&wasm_byte_vec_t>,
) -> bool {
// TODO: review lifetime of byte slice.
let wasm_byte_slice: &[u8] = slice::from_raw_parts(bytes.data, bytes.size);
let store = match store {
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);
false
@@ -51,6 +105,7 @@ pub unsafe extern "C" fn wasm_module_validate(
#[no_mangle]
pub unsafe extern "C" fn wasm_module_exports(
module: &wasm_module_t,
// own
out: &mut wasm_exporttype_vec_t,
) {
let exports = module
@@ -66,6 +121,7 @@ pub unsafe extern "C" fn wasm_module_exports(
#[no_mangle]
pub unsafe extern "C" fn wasm_module_imports(
module: &wasm_module_t,
// own
out: &mut wasm_importtype_vec_t,
) {
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
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;
} else {
(&*bytes).into_slice().unwrap()
@@ -115,3 +174,364 @@ pub unsafe extern "C" fn wasm_module_serialize(
};
*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();
}
}

View File

@@ -1,5 +1,4 @@
use super::engine::wasm_engine_t;
use std::ptr::NonNull;
use wasmer::Store;
/// Opaque wrapper around `Store`
@@ -10,11 +9,10 @@ pub struct wasm_store_t {
#[no_mangle]
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>> {
let wasm_engine_ptr = wasm_engine_ptr?;
let wasm_engine = wasm_engine_ptr.as_ref();
let store = Store::new(&*wasm_engine.inner);
let engine = engine?;
let store = Store::new(&*engine.inner);
Some(Box::new(wasm_store_t { inner: store }))
}

View File

@@ -1,5 +1,6 @@
use super::store::wasm_store_t;
use super::types::{wasm_byte_vec_t, wasm_frame_t, wasm_frame_vec_t, wasm_message_t};
use std::str;
use wasmer::RuntimeError;
// opaque type which is a `RuntimeError`
@@ -19,8 +20,8 @@ pub unsafe extern "C" fn wasm_trap_new(
_store: &mut wasm_store_t,
message: &wasm_message_t,
) -> Option<Box<wasm_trap_t>> {
let message_bytes: &[u8] = message.into_slice()?;
let message_str = c_try!(std::str::from_utf8(message_bytes));
let message_bytes = message.into_slice()?;
let message_str = c_try!(str::from_utf8(message_bytes));
let runtime_error = RuntimeError::new(message_str);
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>>) {}
#[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 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]
@@ -44,10 +50,14 @@ pub unsafe extern "C" fn wasm_trap_origin(trap: &wasm_trap_t) -> Option<Box<wasm
}
#[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 frame_vec: wasm_frame_vec_t = frames.into();
out_ptr.size = frame_vec.size;
out_ptr.data = frame_vec.data;
out.size = frame_vec.size;
out.data = frame_vec.data;
}

View File

@@ -1,59 +1,37 @@
use super::{wasm_externtype_t, wasm_name_t};
use std::ptr::NonNull;
use wasmer::ExportType;
#[allow(non_camel_case_types)]
pub struct wasm_exporttype_t {
name: NonNull<wasm_name_t>,
extern_type: NonNull<wasm_externtype_t>,
/// If `true`, `name` and `extern_type` will be dropped by
/// `wasm_exporttype_t::drop`.
owns_fields: bool,
name: Box<wasm_name_t>,
extern_type: Box<wasm_externtype_t>,
}
wasm_declare_boxed_vec!(exporttype);
#[no_mangle]
pub extern "C" fn wasm_exporttype_new(
name: NonNull<wasm_name_t>,
extern_type: NonNull<wasm_externtype_t>,
) -> Box<wasm_exporttype_t> {
Box::new(wasm_exporttype_t {
name,
extern_type,
owns_fields: false,
})
name: Option<Box<wasm_name_t>>,
extern_type: Option<Box<wasm_externtype_t>>,
) -> Option<Box<wasm_exporttype_t>> {
Some(Box::new(wasm_exporttype_t {
name: name?,
extern_type: extern_type?,
}))
}
#[no_mangle]
pub extern "C" fn wasm_exporttype_name(et: &'static wasm_exporttype_t) -> &'static wasm_name_t {
unsafe { et.name.as_ref() }
pub extern "C" fn wasm_exporttype_name(export_type: &wasm_exporttype_t) -> &wasm_name_t {
export_type.name.as_ref()
}
#[no_mangle]
pub extern "C" fn wasm_exporttype_type(
et: &'static wasm_exporttype_t,
) -> &'static wasm_externtype_t {
unsafe { et.extern_type.as_ref() }
pub extern "C" fn wasm_exporttype_type(export_type: &wasm_exporttype_t) -> &wasm_externtype_t {
export_type.extern_type.as_ref()
}
#[no_mangle]
pub extern "C" fn wasm_exporttype_delete(_exporttype: 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());
}
}
}
}
pub extern "C" fn wasm_exporttype_delete(_export_type: Option<Box<wasm_exporttype_t>>) {}
impl From<ExportType> for wasm_exporttype_t {
fn from(other: ExportType) -> Self {
@@ -63,7 +41,6 @@ impl From<ExportType> for wasm_exporttype_t {
impl From<&ExportType> for wasm_exporttype_t {
fn from(other: &ExportType) -> Self {
// TODO: double check that freeing String as `Vec<u8>` is valid
let name = {
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
let char_ptr = heap_str.as_mut_ptr();
@@ -73,18 +50,12 @@ impl From<&ExportType> for wasm_exporttype_t {
data: char_ptr,
};
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: wasm_externtype_t = other.ty().into();
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) }
};
let extern_type = Box::new(other.ty().into());
wasm_exporttype_t {
name,
extern_type,
owns_fields: true,
}
wasm_exporttype_t { name, extern_type }
}
}

View File

@@ -1,47 +1,13 @@
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::mem;
use thiserror::Error;
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)]
type wasm_externkind_t = u8;
@@ -54,11 +20,6 @@ pub enum wasm_externkind_enum {
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 {
fn from(other: ExternType) -> Self {
(&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]
pub unsafe extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t {
wasm_externkind_enum::from(&et.inner) as wasm_externkind_t
pub unsafe extern "C" fn wasm_extern_type(r#extern: &wasm_extern_t) -> Box<wasm_externtype_t> {
Box::new(wasm_externtype_t::new(r#extern.inner.ty()))
}
#[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)]
@@ -94,7 +127,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_functype_t {
type Error = ExternTypeConversionError;
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) })
} else {
Err(ExternTypeConversionError("Wrong type: expected function"))
@@ -106,7 +139,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
type Error = ExternTypeConversionError;
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) })
} else {
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 {
type Error = ExternTypeConversionError;
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) })
} else {
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]
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> {
Some(c_try!(et.try_into()))
Some(c_try!(extern_type.try_into()))
}
#[no_mangle]
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> {
Some(c_try!(et.try_into()))
Some(c_try!(extern_type.try_into()))
}
#[no_mangle]
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 {
&ft.extern_
&function_type.extern_type
}
#[no_mangle]
pub unsafe extern "C" fn wasm_functype_as_externtype(
ft: &'static wasm_functype_t,
function_type: &'static wasm_functype_t,
) -> &'static wasm_externtype_t {
&ft.extern_
}
#[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_
&function_type.extern_type
}
#[no_mangle]
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> {
Some(c_try!(et.try_into()))
Some(c_try!(extern_type.try_into()))
}
#[no_mangle]
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> {
Some(c_try!(et.try_into()))
Some(c_try!(extern_type.try_into()))
}
#[no_mangle]
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 {
&gt.extern_
&global_type.extern_type
}
#[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_as_externtype(
gt: &'static wasm_globaltype_t,
global_type: &'static wasm_globaltype_t,
) -> &'static wasm_externtype_t {
&gt.extern_
&global_type.extern_type
}
#[no_mangle]
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> {
Some(c_try!(et.try_into()))
Some(c_try!(extern_type.try_into()))
}
#[no_mangle]
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> {
Some(c_try!(et.try_into()))
Some(c_try!(extern_type.try_into()))
}
#[no_mangle]
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 {
&tt.extern_
&table_type.extern_type
}
#[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_as_externtype(
tt: &'static wasm_tabletype_t,
table_type: &'static wasm_tabletype_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
}

View File

@@ -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::ptr::NonNull;
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)]
#[derive(Clone, Debug)]
#[derive(Debug)]
#[repr(transparent)]
pub struct wasm_functype_t {
pub(crate) extern_: wasm_externtype_t,
pub(crate) extern_type: wasm_externtype_t,
}
impl wasm_functype_t {
pub(crate) fn sig(&self) -> &FunctionType {
if let ExternType::Function(ref f) = self.extern_.inner {
f
} else {
unreachable!("data corruption: `wasm_functype_t` does not contain a function")
pub(crate) fn new(function_type: FunctionType) -> Self {
Self {
extern_type: wasm_externtype_t::new(ExternType::Function(function_type)),
}
}
pub(crate) fn new(function_type: FunctionType) -> Self {
Self {
extern_: wasm_externtype_t {
inner: ExternType::Function(function_type),
},
pub(crate) fn inner(&self) -> &WasmFunctionType {
match &self.extern_type.inner {
WasmExternType::Function(wasm_function_type) => &wasm_function_type,
_ => {
unreachable!("Data corruption: `wasm_functype_t` does not contain a function type")
}
}
}
}
@@ -31,88 +94,60 @@ wasm_declare_vec!(functype);
#[no_mangle]
pub unsafe extern "C" fn wasm_functype_new(
// own
params: Option<NonNull<wasm_valtype_vec_t>>,
// own
results: Option<NonNull<wasm_valtype_vec_t>>,
params: Option<Box<wasm_valtype_vec_t>>,
results: Option<Box<wasm_valtype_vec_t>>,
) -> Option<Box<wasm_functype_t>> {
wasm_functype_new_inner(params?, results?)
}
let params = params?;
let results = results?;
unsafe fn wasm_functype_new_inner(
// own
params: NonNull<wasm_valtype_vec_t>,
// own
results: NonNull<wasm_valtype_vec_t>,
) -> Option<Box<wasm_functype_t>> {
let params = params.as_ref();
let results = results.as_ref();
let params: Vec<ValType> = params
let params_as_valtype: Vec<ValType> = params
.into_slice()?
.into_iter()
.map(|val| val.as_ref().into())
.collect::<Vec<_>>();
let results_as_valtype: Vec<ValType> = results
.into_slice()?
.iter()
.map(|ptr| **ptr)
.map(Into::into)
.collect::<Vec<_>>();
let results: Vec<ValType> = results
.into_slice()?
.iter()
.map(|ptr| **ptr)
.map(Into::into)
.map(|val| val.as_ref().into())
.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(
params, results,
params_as_valtype,
results_as_valtype,
))))
}
#[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]
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>> {
let arg = arg?;
let funcsig = arg.as_ref();
Some(Box::new(funcsig.clone()))
let function_type = function_type?;
Some(Box::new(wasm_functype_t::new(
function_type.inner().function_type.clone(),
)))
}
// TODO: fix memory leak
#[no_mangle]
pub unsafe extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
let mut valtypes = ft
.sig()
.params()
.iter()
.cloned()
.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 _
pub unsafe extern "C" fn wasm_functype_params(
function_type: Option<&wasm_functype_t>,
) -> Option<&wasm_valtype_vec_t> {
let function_type = function_type?;
Some(function_type.inner().params.as_ref())
}
// TODO: fix memory leak
#[no_mangle]
pub unsafe extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
let mut valtypes = ft
.sig()
.results()
.iter()
.cloned()
.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 _
pub unsafe extern "C" fn wasm_functype_results(
function_type: Option<&wasm_functype_t>,
) -> Option<&wasm_valtype_vec_t> {
let function_type = function_type?;
Some(function_type.inner().results.as_ref())
}

View File

@@ -1,31 +1,47 @@
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 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)]
#[derive(Clone, Debug)]
#[derive(Debug)]
#[repr(transparent)]
pub struct wasm_globaltype_t {
pub(crate) extern_: wasm_externtype_t,
pub(crate) extern_type: wasm_externtype_t,
}
impl wasm_globaltype_t {
pub(crate) fn as_globaltype(&self) -> &GlobalType {
if let ExternType::Global(ref g) = self.extern_.inner {
g
} else {
unreachable!(
"Data corruption detected: `wasm_globaltype_t` does not contain a `GlobalType`"
);
pub(crate) fn new(global_type: GlobalType) -> Self {
Self {
extern_type: wasm_externtype_t::new(ExternType::Global(global_type)),
}
}
pub(crate) fn new(global_type: GlobalType) -> Self {
Self {
extern_: wasm_externtype_t {
inner: ExternType::Global(global_type),
},
pub(crate) fn inner(&self) -> &WasmGlobalType {
match &self.extern_type.inner {
WasmExternType::Global(wasm_global_type) => &wasm_global_type,
_ => {
unreachable!("Data corruption: `wasm_globaltype_t` does not contain a global type")
}
}
}
}
@@ -34,45 +50,34 @@ wasm_declare_vec!(globaltype);
#[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_new(
// own
valtype: Option<Box<wasm_valtype_t>>,
mutability: wasm_mutability_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]
pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: 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)
}
pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option<Box<wasm_globaltype_t>>) {}
#[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_mutability(
globaltype: &wasm_globaltype_t,
global_type: &wasm_globaltype_t,
) -> wasm_mutability_t {
let gt = globaltype.as_globaltype();
wasm_mutability_enum::from(gt.mutability).into()
wasm_mutability_enum::from(global_type.inner().global_type.mutability).into()
}
// TODO: fix memory leak
// this function leaks memory because the returned limits pointer is not owned
#[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_content(
globaltype: &wasm_globaltype_t,
) -> *const wasm_valtype_t {
let gt = globaltype.as_globaltype();
Box::into_raw(Box::new(gt.ty.into()))
global_type: &wasm_globaltype_t,
) -> &wasm_valtype_t {
global_type.inner().content.as_ref()
}

View File

@@ -1,49 +1,45 @@
use super::{wasm_externtype_t, wasm_name_t};
use std::ptr::NonNull;
use wasmer::ImportType;
// TODO: improve ownership in `importtype_t` (can we safely use `Box<wasm_name_t>` here?)
#[allow(non_camel_case_types)]
pub struct wasm_importtype_t {
pub(crate) module: NonNull<wasm_name_t>,
pub(crate) name: NonNull<wasm_name_t>,
pub(crate) extern_type: NonNull<wasm_externtype_t>,
module: Box<wasm_name_t>,
name: Box<wasm_name_t>,
extern_type: Box<wasm_externtype_t>,
}
wasm_declare_boxed_vec!(importtype);
#[no_mangle]
pub extern "C" fn wasm_importtype_new(
module: NonNull<wasm_name_t>,
name: NonNull<wasm_name_t>,
extern_type: NonNull<wasm_externtype_t>,
) -> Box<wasm_importtype_t> {
Box::new(wasm_importtype_t {
name,
module,
extern_type,
})
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?,
}))
}
#[no_mangle]
pub extern "C" fn wasm_importtype_module(et: &'static wasm_importtype_t) -> &'static wasm_name_t {
unsafe { et.module.as_ref() }
pub extern "C" fn wasm_importtype_module(import_type: &wasm_importtype_t) -> &wasm_name_t {
import_type.module.as_ref()
}
#[no_mangle]
pub extern "C" fn wasm_importtype_name(et: &'static wasm_importtype_t) -> &'static wasm_name_t {
unsafe { et.name.as_ref() }
pub extern "C" fn wasm_importtype_name(import_type: &wasm_importtype_t) -> &wasm_name_t {
import_type.name.as_ref()
}
#[no_mangle]
pub extern "C" fn wasm_importtype_type(
et: &'static wasm_importtype_t,
) -> &'static wasm_externtype_t {
unsafe { et.extern_type.as_ref() }
pub extern "C" fn wasm_importtype_type(import_type: &wasm_importtype_t) -> &wasm_externtype_t {
import_type.extern_type.as_ref()
}
#[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 {
fn from(other: ImportType) -> Self {
@@ -53,7 +49,19 @@ impl From<ImportType> for wasm_importtype_t {
impl From<&ImportType> for wasm_importtype_t {
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 mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
let char_ptr = heap_str.as_mut_ptr();
@@ -63,26 +71,11 @@ impl From<&ImportType> for wasm_importtype_t {
data: char_ptr,
};
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 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))) }
};
let extern_type = Box::new(other.ty().into());
wasm_importtype_t {
name,

View File

@@ -1,49 +1,58 @@
use super::wasm_externtype_t;
use super::{wasm_externtype_t, WasmExternType};
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)]
#[derive(Clone, Debug)]
#[derive(Debug)]
#[repr(transparent)]
pub struct wasm_memorytype_t {
pub(crate) extern_: wasm_externtype_t,
pub(crate) extern_type: wasm_externtype_t,
}
impl wasm_memorytype_t {
pub(crate) fn as_memorytype(&self) -> &MemoryType {
if let ExternType::Memory(ref mt) = self.extern_.inner {
mt
} else {
unreachable!(
"Data corruption detected: `wasm_memorytype_t` does not contain a `MemoryType`"
);
pub(crate) fn new(memory_type: MemoryType) -> Self {
Self {
extern_type: wasm_externtype_t::new(ExternType::Memory(memory_type)),
}
}
pub(crate) fn new(memory_type: MemoryType) -> Self {
Self {
extern_: wasm_externtype_t {
inner: ExternType::Memory(memory_type),
},
pub(crate) fn inner(&self) -> &WasmMemoryType {
match &self.extern_type.inner {
WasmExternType::Memory(wasm_memory_type) => &wasm_memory_type,
_ => {
unreachable!("Data corruption: `wasm_memorytype_t` does not contain a memory type")
}
}
}
}
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]
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {
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 {
None
} else {
@@ -56,19 +65,19 @@ pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm
}
#[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
// this function leaks memory because the returned limits pointer is not owned
#[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> *const wasm_limits_t {
let md = mt.as_memorytype();
Box::into_raw(Box::new(wasm_limits_t {
min: md.minimum.0 as _,
max: md
.maximum
.map(|max| max.0 as _)
.unwrap_or(LIMITS_MAX_SENTINEL),
}))
#[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]
pub unsafe extern "C" fn wasm_memorytype_limits(memory_type: &wasm_memorytype_t) -> &wasm_limits_t {
memory_type.inner().limits.as_ref()
}

View File

@@ -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};
#[allow(non_camel_case_types)]
pub type wasm_table_size_t = u32;
#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
#[repr(C)]
pub struct wasm_tabletype_t {
pub(crate) extern_: wasm_externtype_t,
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
#[derive(Debug, Clone)]
pub(crate) struct WasmTableType {
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 {
pub(crate) fn as_tabletype(&self) -> &TableType {
if let ExternType::Table(ref t) = self.extern_.inner {
t
} else {
unreachable!(
"Data corruption detected: `wasm_tabletype_t` does not contain a `TableType`"
);
Self {
table_type,
limits,
content,
}
}
}
#[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]
pub unsafe extern "C" fn wasm_tabletype_new(
// own
valtype: Box<wasm_valtype_t>,
valtype: Option<Box<wasm_valtype_t>>,
limits: &wasm_limits_t,
) -> Box<wasm_tabletype_t> {
// TODO: investigate if `0` is in fact a sentinel value here
let max_elements = if limits.max == 0 {
) -> Option<Box<wasm_tabletype_t>> {
let valtype = valtype?;
let max_elements = if limits.max == LIMITS_MAX_SENTINEL {
None
} else {
Some(limits.max as _)
};
let out = Box::new(wasm_tabletype_t {
extern_: wasm_externtype_t {
inner: ExternType::Table(TableType::new(
(*valtype).into(),
limits.min as _,
max_elements,
)),
},
});
let table_type = Box::new(wasm_tabletype_t::new(TableType::new(
(*valtype).into(),
limits.min as _,
max_elements,
)));
wasm_valtype_delete(Some(valtype));
out
}
// 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()))
Some(table_type)
}
#[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>>) {}

View File

@@ -60,6 +60,12 @@ wasm_declare_boxed_vec!(valtype);
impl From<wasm_valtype_t> for ValType {
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()
}
}
@@ -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>> {
let kind_enum = kind.try_into().ok()?;
let valtype = wasm_valtype_t { valkind: kind_enum };
Some(Box::new(valtype))
}

View File

@@ -1,6 +1,6 @@
use super::types::{wasm_ref_t, wasm_valkind_enum};
use crate::error::{update_last_error, CApiError};
use std::convert::{TryFrom, TryInto};
use std::ptr::NonNull;
use wasmer::Val;
#[allow(non_camel_case_types)]
@@ -35,25 +35,43 @@ impl Clone for wasm_val_t {
}
#[no_mangle]
pub unsafe extern "C" fn wasm_val_copy(out_ptr: *mut wasm_val_t, val: &wasm_val_t) {
(*out_ptr).kind = val.kind;
(*out_ptr).of =
// TODO: handle this error
match val.kind.try_into().unwrap() {
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 },
pub unsafe extern "C" fn wasm_val_copy(
// own
out: &mut wasm_val_t,
val: &wasm_val_t,
) {
out.kind = val.kind;
out.of = match val.kind.try_into() {
Ok(kind) => match kind {
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_FUNCREF => wasm_val_inner { wref: val.of.wref },
};
},
Err(e) => {
update_last_error(CApiError { msg: e.to_string() });
return;
}
};
}
#[no_mangle]
pub unsafe extern "C" fn wasm_val_delete(val: Option<NonNull<wasm_val_t>>) {
if let Some(v_inner) = val {
pub unsafe extern "C" fn wasm_val_delete(val: Option<Box<wasm_val_t>>) {
if let Some(val) = val {
// TODO: figure out where wasm_val is allocated first...
let _ = Box::from_raw(v_inner.as_ptr());
let _ = val;
}
}

View File

@@ -6,7 +6,11 @@ use std::str;
use std::sync::Arc;
#[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() {
Some(name) => name,
None => return,
@@ -18,7 +22,8 @@ pub unsafe extern "C" fn wasm_module_name(module: &wasm_module_t, out: &mut wasm
#[no_mangle]
pub unsafe extern "C" fn wasm_module_set_name(
module: &mut wasm_module_t,
name: &wasm_name_t,
// own
name: Box<wasm_name_t>,
) -> bool {
let name = match name.into_slice() {
Some(name) => match str::from_utf8(name) {

View File

@@ -12,3 +12,71 @@ pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t) -> Option<Box<wasm_byte
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();
}
}

View File

@@ -4,14 +4,14 @@ project (WasmerWasmCApiTests)
# 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-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-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-reflect wasm-c-api/example/reflect.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-threads wasm-c-api/example/threads.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/
#)
#target_link_libraries(wasm-c-api-global general ${WASMER_LIB})
#target_compile_options(wasm-c-api-global PRIVATE ${COMPILER_OPTIONS})
#add_test(NAME wasm-c-api-global
# COMMAND wasm-c-api-global
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
#)
target_link_libraries(wasm-c-api-global general ${WASMER_LIB})
target_compile_options(wasm-c-api-global PRIVATE ${COMPILER_OPTIONS})
add_test(NAME wasm-c-api-global
COMMAND wasm-c-api-global
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
)
target_link_libraries(wasm-c-api-hello general ${WASMER_LIB})
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/
#)
#target_link_libraries(wasm-c-api-memory general ${WASMER_LIB})
#target_compile_options(wasm-c-api-memory PRIVATE ${COMPILER_OPTIONS})
#add_test(NAME wasm-c-api-memory
# COMMAND wasm-c-api-memory
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
#)
target_link_libraries(wasm-c-api-memory general ${WASMER_LIB})
target_compile_options(wasm-c-api-memory PRIVATE ${COMPILER_OPTIONS})
add_test(NAME wasm-c-api-memory
COMMAND wasm-c-api-memory
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
)
#target_link_libraries(wasm-c-api-multi general ${WASMER_LIB})
#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/
)
#target_link_libraries(wasm-c-api-start general ${WASMER_LIB})
#target_compile_options(wasm-c-api-start PRIVATE ${COMPILER_OPTIONS})
#add_test(NAME wasm-c-api-start
# COMMAND wasm-c-api-start
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
#)
target_link_libraries(wasm-c-api-start general ${WASMER_LIB})
target_compile_options(wasm-c-api-start PRIVATE ${COMPILER_OPTIONS})
add_test(NAME wasm-c-api-start
COMMAND wasm-c-api-start
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example/
)
#target_link_libraries(wasm-c-api-table general ${WASMER_LIB})
#target_compile_options(wasm-c-api-table PRIVATE ${COMPILER_OPTIONS})

View 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 */

View File

@@ -29,6 +29,9 @@
# define DEPRECATED(message) __declspec(deprecated(message))
#endif
// The `jit` feature has been enabled for this build.
#define WASMER_JIT_ENABLED
// The `compiler` feature has been enabled for this build.
#define WASMER_COMPILER_ENABLED
@@ -53,7 +56,10 @@
#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 {
CRANELIFT = 0,
@@ -61,6 +67,12 @@ typedef enum {
SINGLEPASS = 2,
} 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 {
JIT = 0,
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);
#endif
/**
* Configure the compiler to use.
*/
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_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.

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-cache"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Cache system for Wasmer WebAssembly runtime"
categories = ["wasm", "caching"]
keywords = ["wasm", "webassembly", "cache"]
@@ -11,7 +11,7 @@ readme = "README.md"
edition = "2018"
[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"
hex = "0.4"
thiserror = "1"

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-cli"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer CLI"
categories = ["wasm", "command-line-interface"]
keywords = ["wasm", "webassembly", "cli"]
@@ -17,22 +17,22 @@ path = "src/bin/wasmer.rs"
doc = false
[dependencies]
wasmer = { version = "1.0.0-alpha4", path = "../api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha4", path = "../compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha4", path = "../compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha4", path = "../compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha4", path = "../compiler-llvm", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha4", path = "../emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha4", path = "../engine" }
wasmer-engine-jit = { version = "1.0.0-alpha4", path = "../engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha4", path = "../engine-native", optional = true }
wasmer-engine-object-file = { version = "1.0.0-alpha4", path = "../engine-object-file", optional = true }
wasmer-vm = { version = "1.0.0-alpha4", path = "../vm" }
wasmer-wasi = { version = "1.0.0-alpha4", path = "../wasi", optional = true }
wasmer-wasi-experimental-io-devices = { version = "1.0.0-alpha4", path = "../wasi-experimental-io-devices", optional = true }
wasmer-wast = { version = "1.0.0-alpha4", path = "../../tests/lib/wast", optional = true }
wasmer-cache = { version = "1.0.0-alpha4", path = "../cache", optional = true }
wasmer-types = { version = "1.0.0-alpha4", path = "../wasmer-types" }
wasmer = { version = "1.0.0-alpha5", path = "../api", default-features = false }
wasmer-compiler = { version = "1.0.0-alpha5", path = "../compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "../compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "../compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "../compiler-llvm", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha5", path = "../emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha5", path = "../engine" }
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "../engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha5", path = "../engine-native", optional = true }
wasmer-engine-object-file = { version = "1.0.0-alpha5", path = "../engine-object-file", optional = true }
wasmer-vm = { version = "1.0.0-alpha5", path = "../vm" }
wasmer-wasi = { version = "1.0.0-alpha5", path = "../wasi", 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-alpha5", path = "../../tests/lib/wast", optional = true }
wasmer-cache = { version = "1.0.0-alpha5", path = "../cache", optional = true }
wasmer-types = { version = "1.0.0-alpha5", path = "../wasmer-types" }
atty = "0.2"
colored = "2.0"
anyhow = "1.0"
@@ -41,7 +41,7 @@ structopt = { version = "0.3", features = ["suggestions"] }
distance = "0.4"
# For the inspect subcommand
bytesize = "1.0"
cfg-if = "0.1"
cfg-if = "1.0"
# For debug feature
fern = { version = "0.6", features = ["colored"], optional = true }
log = { version = "0.4", optional = true }

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-compiler-cranelift"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Cranelift compiler for Wasmer WebAssembly runtime"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "compiler", "cranelift"]
@@ -12,21 +12,22 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"], default-features = false }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4", default-features = false, features = ["std"] }
cranelift-codegen = { version = "0.65", default-features = false, features = ["x86", "arm64"] }
cranelift-frontend = { version = "0.65", 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-alpha5" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5", default-features = false, features = ["std"] }
cranelift-codegen = { version = "0.67", default-features = false, features = ["x86", "arm64"] }
cranelift-frontend = { version = "0.67", default-features = false }
tracing = "0.1"
hashbrown = { version = "0.8", optional = true }
rayon = "1.3"
hashbrown = { version = "0.9", optional = true }
rayon = "1.5"
serde = { version = "1.0", features = ["derive"] }
more-asserts = "0.2"
gimli = { version = "0.21", optional = true }
smallvec = "1.0.0"
[dev-dependencies]
target-lexicon = { version = "0.10", default-features = false }
cranelift-codegen = { version = "0.65", features = ["enable-serde", "all-arch"] }
target-lexicon = { version = "0.11", default-features = false }
cranelift-codegen = { version = "0.67", features = ["enable-serde", "all-arch"] }
lazy_static = "1.4"
[badges]
@@ -35,6 +36,6 @@ maintenance = { status = "actively-developed" }
[features]
default = ["std", "enable-serde", "unwind"]
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"]
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]

View File

@@ -95,7 +95,7 @@ impl Compiler for CraneliftCompiler {
};
let functions = function_body_inputs
.into_iter()
.iter()
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
.par_iter()
.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 reloc_sink = RelocSink::new(module, func_index);
let mut trap_sink = TrapSink::new();
let mut stackmap_sink = binemit::NullStackmapSink {};
let mut stackmap_sink = binemit::NullStackMapSink {};
context
.compile_and_emit(
&*isa,

View File

@@ -11,7 +11,9 @@ use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Signature};
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_frontend::FunctionBuilder;
use std::convert::TryFrom;
use wasmer_compiler::wasmparser::Type;
use wasmer_compiler::{WasmError, WasmResult};
use wasmer_types::entity::EntityRef;
use wasmer_types::entity::PrimaryMap;
@@ -538,10 +540,11 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_grow(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: TableIndex,
_: ir::Value,
_: ir::Value,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
_table_index: TableIndex,
_table: ir::Table,
_delta: ir::Value,
_init_value: ir::Value,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
"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(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: TableIndex,
_: ir::Value,
_builder: &mut FunctionBuilder,
_table_index: TableIndex,
_table: ir::Table,
_index: ir::Value,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
"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(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: TableIndex,
_: ir::Value,
_: ir::Value,
_builder: &mut FunctionBuilder,
_table_index: TableIndex,
_table: ir::Table,
_value: ir::Value,
_index: ir::Value,
) -> WasmResult<()> {
Err(WasmError::Unsupported(
"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(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: TableIndex,
_: ir::Value,
_: ir::Value,
_: ir::Value,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
_table_index: TableIndex,
_dst: ir::Value,
_val: ir::Value,
_len: ir::Value,
) -> WasmResult<()> {
Err(WasmError::Unsupported(
"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(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: u32,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
_func_index: FunctionIndex,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
"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(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: GlobalIndex,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
_index: GlobalIndex,
) -> WasmResult<ir::Value> {
unreachable!("we don't make any custom globals")
}
fn translate_custom_global_set(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: GlobalIndex,
_: ir::Value,
mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
_index: GlobalIndex,
_value: ir::Value,
) -> WasmResult<()> {
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] {
TableStyle::CallerChecksSignature => {
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 base = pos.ins().global_value(pointer_type, vmctx);
let offset =
@@ -897,24 +937,22 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_memory_copy(
&mut self,
mut pos: FuncCursor,
memory_index: MemoryIndex,
_heap: ir::Heap,
src_index: MemoryIndex,
_src_heap: ir::Heap,
_dst_index: MemoryIndex,
_dst_heap: ir::Heap,
dst: ir::Value,
src: ir::Value,
len: ir::Value,
) -> WasmResult<()> {
let (func_sig, memory_index, func_idx) =
self.get_memory_copy_func(&mut pos.func, memory_index);
let (func_sig, src_index, func_idx) = self.get_memory_copy_func(&mut pos.func, src_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);
pos.ins().call_indirect(
func_sig,
func_addr,
&[vmctx, memory_index_arg, dst, src, len],
);
pos.ins()
.call_indirect(func_sig, func_addr, &[vmctx, src_index_arg, dst, src, len]);
Ok(())
}
@@ -981,8 +1019,8 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
fn translate_table_size(
&mut self,
_pos: FuncCursor,
_index: TableIndex,
mut _pos: FuncCursor,
_table_index: TableIndex,
_table: ir::Table,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
@@ -1064,4 +1102,31 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
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(),
))
}
}

View File

@@ -3,7 +3,7 @@
use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind};
use cranelift_codegen::binemit;
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::{FunctionIndex, LocalFunctionIndex};
use wasmer_vm::{ModuleInfo, TrapCode};
@@ -108,12 +108,11 @@ impl binemit::TrapSink for TrapSink {
fn trap(
&mut self,
code_offset: binemit::CodeOffset,
source_loc: ir::SourceLoc,
_source_loc: ir::SourceLoc,
trap_code: ir::TrapCode,
) {
self.traps.push(TrapInformation {
code_offset,
source_loc: SourceLoc::new(source_loc.bits()),
// TODO: Translate properly environment Trapcode into cranelift IR
trap_code: translate_ir_trapcode(trap_code),
});
@@ -125,6 +124,7 @@ fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
match trap {
ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds,
ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned,
ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds,
ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
ir::TrapCode::BadSignature => TrapCode::BadSignature,

View File

@@ -110,7 +110,7 @@ pub fn make_trampoline_dynamic_function(
let mut code_buf = Vec::new();
let mut reloc_sink = TrampolineRelocSink {};
let mut trap_sink = binemit::NullTrapSink {};
let mut stackmap_sink = binemit::NullStackmapSink {};
let mut stackmap_sink = binemit::NullStackMapSink {};
context
.compile_and_emit(
isa,

View File

@@ -108,7 +108,7 @@ pub fn make_trampoline_function_call(
let mut code_buf = Vec::new();
let mut reloc_sink = TrampolineRelocSink {};
let mut trap_sink = binemit::NullTrapSink {};
let mut stackmap_sink = binemit::NullStackmapSink {};
let mut stackmap_sink = binemit::NullStackMapSink {};
context
.compile_and_emit(

View File

@@ -6,19 +6,13 @@ mod function_call;
pub use self::dynamic_function::make_trampoline_dynamic_function;
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::Context;
pub use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
pub mod binemit {
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};

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ use cranelift_codegen::ir::immediates::Offset32;
use cranelift_codegen::ir::{self, InstBuilder};
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_frontend::FunctionBuilder;
use wasmer_compiler::wasmparser::Operator;
use wasmer_compiler::wasmparser::{Operator, Type};
use wasmer_compiler::WasmResult;
use wasmer_types::{FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex};
@@ -229,8 +229,10 @@ pub trait FuncEnvironment: TargetEnvironment {
fn translate_memory_copy(
&mut self,
pos: FuncCursor,
index: MemoryIndex,
heap: ir::Heap,
src_index: MemoryIndex,
src_heap: ir::Heap,
dst_index: MemoryIndex,
dst_heap: ir::Heap,
dst: ir::Value,
src: ir::Value,
len: ir::Value,
@@ -283,6 +285,7 @@ pub trait FuncEnvironment: TargetEnvironment {
&mut self,
pos: FuncCursor,
table_index: TableIndex,
table: ir::Table,
delta: ir::Value,
init_value: ir::Value,
) -> WasmResult<ir::Value>;
@@ -290,16 +293,18 @@ pub trait FuncEnvironment: TargetEnvironment {
/// Translate a `table.get` WebAssembly instruction.
fn translate_table_get(
&mut self,
pos: FuncCursor,
builder: &mut FunctionBuilder,
table_index: TableIndex,
table: ir::Table,
index: ir::Value,
) -> WasmResult<ir::Value>;
/// Translate a `table.set` WebAssembly instruction.
fn translate_table_set(
&mut self,
pos: FuncCursor,
builder: &mut FunctionBuilder,
table_index: TableIndex,
table: ir::Table,
value: ir::Value,
index: ir::Value,
) -> WasmResult<()>;
@@ -344,8 +349,44 @@ pub trait FuncEnvironment: TargetEnvironment {
/// Translate a `elem.drop` WebAssembly instruction.
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.
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
/// that is custom.
@@ -364,6 +405,38 @@ pub trait FuncEnvironment: TargetEnvironment {
val: ir::Value,
) -> 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.
///
/// This can be used to insert explicit interrupt or safepoint checking at

View File

@@ -132,7 +132,9 @@ impl ControlStackFrame {
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 {
Self::If {
original_stack_size,
@@ -182,6 +184,33 @@ impl ControlStackFrame {
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:
@@ -219,6 +248,16 @@ pub struct FuncTranslationState {
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 {
/// Construct a new, empty, `FuncTranslationState`
pub(crate) fn new() -> Self {
@@ -441,7 +480,7 @@ impl FuncTranslationState {
/// Get the `Table` reference that should be used to access table `index`.
/// 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,
func: &mut ir::Function,
index: u32,

View File

@@ -176,12 +176,9 @@ fn parse_local_decls<FE: FuncEnvironment + ?Sized>(
let mut next_local = num_params;
let local_count = reader.read_local_count().map_err(to_wasm_error)?;
let mut locals_total = 0;
for _ in 0..local_count {
builder.set_srcloc(cur_srcloc(reader));
let (count, ty) = reader
.read_local_decl(&mut locals_total)
.map_err(to_wasm_error)?;
let (count, ty) = reader.read_local_decl().map_err(to_wasm_error)?;
declare_locals(builder, count, ty, &mut next_local, environ)?;
}

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-compiler-llvm"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "LLVM compiler for Wasmer WebAssembly runtime"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "compiler", "llvm"]
@@ -12,16 +12,16 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"] }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
target-lexicon = { version = "0.10", default-features = false }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"] }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
target-lexicon = { version = "0.11", default-features = false }
smallvec = "1"
goblin = "0.2"
libc = { version = "^0.2.69", default-features = false }
libc = { version = "^0.2", default-features = false }
byteorder = "1"
itertools = "0.9"
rayon = "1.3"
rayon = "1.5"
[dependencies.inkwell]
version = "=0.1.0-llvm10sample"

View File

@@ -124,7 +124,7 @@ impl LLVMCompiler {
compile_info
.module
.signatures
.into_iter()
.iter()
.collect::<Vec<_>>()
.par_iter()
.map_init(
@@ -149,7 +149,7 @@ impl LLVMCompiler {
compile_info
.module
.functions
.into_iter()
.iter()
.collect::<Vec<_>>()
.par_iter()
.map_init(
@@ -248,7 +248,7 @@ impl Compiler for LLVMCompiler {
let mut frame_section_bytes = vec![];
let mut frame_section_relocations = vec![];
let functions = function_body_inputs
.into_iter()
.iter()
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
.par_iter()
.map_init(

View File

@@ -184,10 +184,7 @@ impl FuncTranslator {
let mut locals = vec![];
let num_locals = reader.read_local_count().map_err(to_wasm_error)?;
for _ in 0..num_locals {
let mut counter = 0;
let (count, ty) = reader
.read_local_decl(&mut counter)
.map_err(to_wasm_error)?;
let (count, ty) = reader.read_local_decl().map_err(to_wasm_error)?;
let ty = wptype_to_type(ty).map_err(to_compile_error)?;
let ty = type_to_llvm(&intrinsics, ty)?;
for _ in 0..count {
@@ -1110,21 +1107,13 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
}
fn trap_if_misaligned(&self, memarg: &MemoryImmediate, ptr: PointerValue<'ctx>) {
let align = match memarg.flags & 3 {
0 => {
return; /* No alignment to check. */
}
1 => 2,
2 => 4,
3 => 8,
_ => unreachable!("this match is fully covered"),
};
let align = memarg.align;
let value = self
.builder
.build_ptr_to_int(ptr, self.intrinsics.i64_ty, "");
let and = self.builder.build_and(
value,
self.intrinsics.i64_ty.const_int(align - 1, false),
self.intrinsics.i64_ty.const_int((align - 1).into(), false),
"misaligncheck",
);
let aligned =
@@ -1541,7 +1530,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
.get_insert_block()
.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()?;
@@ -1561,7 +1554,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let cases: Vec<_> = label_depths
.iter()
.enumerate()
.map(|(case_index, &depth)| {
.map(|(case_index, &(depth, _))| {
let frame_result: Result<&ControlFrame, CompileError> =
self.state.frame_at_depth(depth);
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, "");
self.state.push1(res);
}
Operator::I8x16AddSaturateS => {
Operator::I8x16AddSatS => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i8x16(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I16x8AddSaturateS => {
Operator::I16x8AddSatS => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i16x8(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I8x16AddSaturateU => {
Operator::I8x16AddSatU => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i8x16(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I16x8AddSaturateU => {
Operator::I16x8AddSatU => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i16x8(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I8x16SubSaturateS => {
Operator::I8x16SubSatS => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i8x16(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I16x8SubSaturateS => {
Operator::I16x8SubSatS => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i16x8(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I8x16SubSaturateU => {
Operator::I8x16SubSatU => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i8x16(v1, i1);
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, "");
self.state.push1(res);
}
Operator::I16x8SubSaturateU => {
Operator::I16x8SubSatU => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let (v1, _) = self.v128_into_i16x8(v1, i1);
let (v2, _) = self.v128_into_i16x8(v2, i2);
@@ -6975,7 +6968,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
};
self.state.push1_extra(res, info);
}
Operator::V8x16Swizzle => {
Operator::I8x16Swizzle => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let v1 = self.apply_pending_canonicalization(v1, i1);
let v1 = self
@@ -7043,7 +7036,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
self.state.push1(res);
}
Operator::V8x16Shuffle { lanes } => {
Operator::I8x16Shuffle { lanes } => {
let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?;
let v1 = self.apply_pending_canonicalization(v1, i1);
let v1 = self
@@ -7066,7 +7059,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, "");
self.state.push1(res);
}
Operator::I16x8Load8x8S { ref memarg } => {
Operator::V128Load8x8S { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::I16x8Load8x8U { ref memarg } => {
Operator::V128Load8x8U { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::I32x4Load16x4S { ref memarg } => {
Operator::V128Load16x4S { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::I32x4Load16x4U { ref memarg } => {
Operator::V128Load16x4U { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::I64x2Load32x2S { ref memarg } => {
Operator::V128Load32x2S { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::I64x2Load32x2U { ref memarg } => {
Operator::V128Load32x2U { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
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 memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::V16x8LoadSplat { ref memarg } => {
Operator::V128Load16Splat { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::V32x4LoadSplat { ref memarg } => {
Operator::V128Load32Splat { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
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, "");
self.state.push1(res);
}
Operator::V64x2LoadSplat { ref memarg } => {
Operator::V128Load64Splat { ref memarg } => {
let offset = self.state.pop1()?.into_int_value();
let memory_index = MemoryIndex::from_u32(0);
let effective_address = self.resolve_memory_ptr(
@@ -9246,8 +9287,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
self.state.push1(old);
}
Operator::MemoryGrow { reserved } => {
let memory_index = MemoryIndex::from_u32(reserved);
Operator::MemoryGrow { mem, mem_byte: _ } => {
let memory_index = MemoryIndex::from_u32(mem);
let delta = self.state.pop1()?;
let grow_fn_ptr = self.ctx.memory_grow(memory_index, self.intrinsics);
let grow = self.builder.build_call(
@@ -9257,15 +9298,15 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
delta,
self.intrinsics
.i32_ty
.const_int(reserved.into(), false)
.const_int(mem.into(), false)
.as_basic_value_enum(),
],
"",
);
self.state.push1(grow.try_as_basic_value().left().unwrap());
}
Operator::MemorySize { reserved } => {
let memory_index = MemoryIndex::from_u32(reserved);
Operator::MemorySize { mem, mem_byte: _ } => {
let memory_index = MemoryIndex::from_u32(mem);
let size_fn_ptr = self.ctx.memory_size(memory_index, self.intrinsics);
let size = self.builder.build_call(
size_fn_ptr,
@@ -9273,7 +9314,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
vmctx.as_basic_value_enum(),
self.intrinsics
.i32_ty
.const_int(reserved.into(), false)
.const_int(mem.into(), false)
.as_basic_value_enum(),
],
"",

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-compiler-singlepass"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Singlepass compiler for Wasmer WebAssembly runtime"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "compiler", "singlepass"]
@@ -12,11 +12,11 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"], default-features = false }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4", default-features = false, features = ["std"] }
rayon = "1.3"
hashbrown = { version = "0.8", optional = true }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"], default-features = false }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5", default-features = false, features = ["std"] }
rayon = "1.5"
hashbrown = { version = "0.9", optional = true }
serde = { version = "1.0", features = ["derive"] }
more-asserts = "0.2"
dynasm = "1.0"

View File

@@ -1316,17 +1316,7 @@ impl<'a> FuncGen<'a> {
self.machine.release_temp_gpr(tmp_bound);
self.machine.release_temp_gpr(tmp_base);
let align = match memarg.flags & 3 {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
_ => {
return Err(CodegenError {
message: "emit_memory_op align: unreachable value".to_string(),
})
}
};
let align = memarg.align;
if check_alignment && align != 1 {
let tmp_aligncheck = self.machine.acquire_temp_gpr().unwrap();
self.assembler.emit_mov(
@@ -1336,7 +1326,7 @@ impl<'a> FuncGen<'a> {
);
self.assembler.emit_and(
Size::S64,
Location::Imm32(align - 1),
Location::Imm32((align - 1).into()),
Location::GPR(tmp_aligncheck),
);
self.assembler
@@ -5615,8 +5605,8 @@ impl<'a> FuncGen<'a> {
// TODO: Re-enable interrupt signal check without branching
}
Operator::Nop => {}
Operator::MemorySize { reserved } => {
let memory_index = MemoryIndex::new(reserved as usize);
Operator::MemorySize { mem, mem_byte: _ } => {
let memory_index = MemoryIndex::new(mem as usize);
self.assembler.emit_mov(
Size::S64,
Location::Memory(
@@ -5653,8 +5643,8 @@ impl<'a> FuncGen<'a> {
self.assembler
.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
}
Operator::MemoryGrow { reserved } => {
let memory_index = MemoryIndex::new(reserved as usize);
Operator::MemoryGrow { mem, mem_byte: _ } => {
let memory_index = MemoryIndex::new(mem as usize);
let param_pages = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[param_pages]);
@@ -6304,9 +6294,13 @@ impl<'a> FuncGen<'a> {
self.assembler.emit_label(after);
}
Operator::BrTable { ref table } => {
let (targets, default_target) = table.read_table().map_err(|e| CodegenError {
message: format!("BrTable read_table: {:?}", e),
})?;
let mut targets = table
.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 table_label = self.assembler.get_label();
let mut table: Vec<DynamicLabel> = vec![];
@@ -6334,7 +6328,7 @@ impl<'a> FuncGen<'a> {
);
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();
self.assembler.emit_label(label);
table.push(label);
@@ -8179,7 +8173,6 @@ impl<'a> FuncGen<'a> {
.into_iter()
.map(|(offset, code)| TrapInformation {
code_offset: offset as u32,
source_loc: Default::default(),
trap_code: code,
})
.collect(),

View File

@@ -69,7 +69,7 @@ impl Compiler for SinglepassCompiler {
.into_iter()
.collect();
let functions = function_body_inputs
.into_iter()
.iter()
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
.par_iter()
.map(|(i, input)| {
@@ -82,10 +82,7 @@ impl Compiler for SinglepassCompiler {
let mut locals = vec![];
let num_locals = reader.read_local_count().map_err(to_compile_error)?;
for _ in 0..num_locals {
let mut counter = 0;
let (count, ty) = reader
.read_local_decl(&mut counter)
.map_err(to_compile_error)?;
let (count, ty) = reader.read_local_decl().map_err(to_compile_error)?;
for _ in 0..count {
locals.push(ty);
}

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-compiler"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Base compiler abstraction for Wasmer WebAssembly runtime"
categories = ["wasm", "no-std"]
keywords = ["wasm", "webassembly", "compiler"]
@@ -11,12 +11,12 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4", default-features = false }
wasmparser = { version = "0.57", optional = true, default-features = false }
target-lexicon = { version = "0.10", default-features = false }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5", default-features = false }
wasmparser = { version = "0.65", optional = true, default-features = false }
target-lexicon = { version = "0.11", default-features = false }
enumset = "1.0"
hashbrown = { version = "0.8", optional = true }
hashbrown = { version = "0.9", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "1.0"
serde_bytes = { version = "0.11", optional = true }

View File

@@ -13,7 +13,7 @@ use crate::ModuleTranslationState;
use crate::SectionIndex;
use wasmer_types::entity::PrimaryMap;
use wasmer_types::{Features, FunctionIndex, LocalFunctionIndex, SignatureIndex};
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
use wasmparser::{Validator, WasmFeatures};
/// The compiler configuration options.
pub trait CompilerConfig {
@@ -58,17 +58,24 @@ pub trait Compiler {
features: &Features,
data: &'data [u8],
) -> Result<(), CompileError> {
let config = ValidatingParserConfig {
operator_config: OperatorValidatorConfig {
enable_threads: features.threads,
enable_reference_types: features.reference_types,
enable_bulk_memory: features.bulk_memory,
enable_tail_call: false,
enable_simd: features.simd,
enable_multi_value: features.multi_value,
},
let mut validator = Validator::new();
let wasm_features = WasmFeatures {
bulk_memory: features.bulk_memory,
threads: features.threads,
reference_types: features.reference_types,
multi_value: features.multi_value,
simd: features.simd,
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.

View File

@@ -94,13 +94,15 @@ impl<'a> MiddlewareBinaryReader<'a> {
}
/// Read a `count` indicating the number of times to call `read_local_decl`.
pub fn read_local_count(&mut self) -> WpResult<usize> {
self.state.inner.read_local_count()
pub fn read_local_count(&mut self) -> WpResult<u32> {
self.state.inner.read_var_u32()
}
/// 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)> {
self.state.inner.read_local_decl(locals_total)
pub fn read_local_decl(&mut self) -> WpResult<(u32, Type)> {
let count = self.state.inner.read_var_u32()?;
let ty = self.state.inner.read_type()?;
Ok((count, ty))
}
/// Reads the next available `Operator`.

View File

@@ -6,13 +6,13 @@
use super::environ::ModuleEnvironment;
use super::error::to_wasm_error;
use super::sections::{
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
parse_data_section, parse_element_section, parse_export_section, parse_function_section,
parse_global_section, parse_import_section, parse_memory_section, parse_name_section,
parse_start_section, parse_table_section, parse_type_section,
};
use super::state::ModuleTranslationState;
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
/// parsed ModuleInfo `ModuleTranslationState`.
@@ -20,75 +20,88 @@ pub fn translate_module<'data>(
data: &'data [u8],
environ: &mut ModuleEnvironment<'data>,
) -> WasmResult<ModuleTranslationState> {
let mut reader = ModuleReader::new(data).map_err(to_wasm_error)?;
let mut module_translation_state = ModuleTranslationState::new();
while !reader.eof() {
let section = reader.read().map_err(to_wasm_error)?;
match section.content().map_err(to_wasm_error)? {
SectionContent::Type(types) => {
for payload in Parser::new(0).parse_all(data) {
match payload.map_err(to_wasm_error)? {
Payload::Version { .. } | Payload::End => {}
Payload::TypeSection(types) => {
parse_type_section(types, &mut module_translation_state, environ)?;
}
SectionContent::Import(imports) => {
Payload::ImportSection(imports) => {
parse_import_section(imports, environ)?;
}
SectionContent::Function(functions) => {
Payload::FunctionSection(functions) => {
parse_function_section(functions, environ)?;
}
SectionContent::Table(tables) => {
Payload::TableSection(tables) => {
parse_table_section(tables, environ)?;
}
SectionContent::Memory(memories) => {
Payload::MemorySection(memories) => {
parse_memory_section(memories, environ)?;
}
SectionContent::Global(globals) => {
Payload::GlobalSection(globals) => {
parse_global_section(globals, environ)?;
}
SectionContent::Export(exports) => {
Payload::ExportSection(exports) => {
parse_export_section(exports, environ)?;
}
SectionContent::Start(start) => {
parse_start_section(start, environ)?;
Payload::StartSection { func, .. } => {
parse_start_section(func, environ)?;
}
SectionContent::Element(elements) => {
Payload::ElementSection(elements) => {
parse_element_section(elements, environ)?;
}
SectionContent::Code(code) => {
parse_code_section(code, &module_translation_state, environ)?;
Payload::CodeSectionStart { .. } => {}
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)?;
}
SectionContent::DataCount(count) => {
Payload::DataCountSection { count, .. } => {
environ.reserve_passive_data(count)?;
}
SectionContent::Custom {
name,
binary,
content,
} => match content {
Some(CustomSectionContent::Name(names)) => {
parse_name_section(names, environ)?;
}
_ => {
let mut reader = binary.clone();
let len = reader.bytes_remaining();
let payload = reader.read_bytes(len).map_err(to_wasm_error)?;
environ.custom_section(name, payload)?;
}
},
Payload::ModuleSection(_)
| Payload::InstanceSection(_)
| Payload::AliasSection(_)
| Payload::ModuleCodeSectionStart { .. }
| Payload::ModuleCodeSectionEntry { .. } => {
unimplemented!("module linking not implemented yet")
}
Payload::CustomSection {
name: "name",
data,
data_offset,
} => 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!(),
}
}

View File

@@ -26,12 +26,11 @@ use wasmer_types::{
MemoryIndex, MemoryType, Pages, SignatureIndex, TableIndex, TableType, Type, V128,
};
use wasmparser::{
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems,
ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind,
FuncType as WPFunctionType, FunctionSectionReader, GlobalSectionReader,
GlobalType as WPGlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader,
MemoryType as WPMemoryType, NameSectionReader, Naming, NamingReader, Operator,
TableSectionReader, TypeSectionReader,
self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind,
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType as WPFunctionType,
FunctionSectionReader, GlobalSectionReader, GlobalType as WPGlobalType, ImportSectionEntryType,
ImportSectionReader, MemorySectionReader, MemoryType as WPMemoryType, NameSectionReader,
Naming, NamingReader, Operator, TableSectionReader, TypeDef, TypeSectionReader,
};
/// Helper function translating wasmparser types to Wasm Type.
@@ -61,25 +60,29 @@ pub fn parse_type_section(
environ.reserve_signatures(count)?;
for entry in types {
let WPFunctionType { params, returns } = entry.map_err(to_wasm_error)?;
let sig_params: Vec<Type> = params
.iter()
.map(|ty| {
wptype_to_type(*ty)
.expect("only numeric types are supported in function signatures")
})
.collect();
let sig_returns: Vec<Type> = returns
.iter()
.map(|ty| {
wptype_to_type(*ty)
.expect("only numeric types are supported in function signatures")
})
.collect();
let sig = FunctionType::new(sig_params, sig_returns);
environ.declare_signature(sig)?;
module_translation_state.wasm_types.push((params, returns));
if let Ok(TypeDef::Func(WPFunctionType { params, returns })) = entry {
let sig_params: Vec<Type> = params
.iter()
.map(|ty| {
wptype_to_type(*ty)
.expect("only numeric types are supported in function signatures")
})
.collect();
let sig_returns: Vec<Type> = returns
.iter()
.map(|ty| {
wptype_to_type(*ty)
.expect("only numeric types are supported in function signatures")
})
.collect();
let sig = FunctionType::new(sig_params, sig_returns);
environ.declare_signature(sig)?;
module_translation_state.wasm_types.push((params, returns));
} else {
unimplemented!("module linking not implemented yet")
}
}
Ok(())
}
@@ -100,10 +103,13 @@ pub fn parse_import_section<'data>(
environ.declare_func_import(
SignatureIndex::from_u32(sig),
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,
shared,
}) => {
@@ -114,9 +120,12 @@ pub fn parse_import_section<'data>(
shared,
},
module_name,
field_name,
field_name.unwrap_or_default(),
)?;
}
ImportSectionEntryType::Memory(WPMemoryType::M64 { .. }) => {
unimplemented!("64bit memory not implemented yet")
}
ImportSectionEntryType::Global(ref ty) => {
environ.declare_global_import(
GlobalType {
@@ -124,7 +133,7 @@ pub fn parse_import_section<'data>(
mutability: ty.mutable.into(),
},
module_name,
field_name,
field_name.unwrap_or_default(),
)?;
}
ImportSectionEntryType::Table(ref tab) => {
@@ -135,7 +144,7 @@ pub fn parse_import_section<'data>(
maximum: tab.limits.maximum,
},
module_name,
field_name,
field_name.unwrap_or_default(),
)?;
}
}
@@ -194,11 +203,16 @@ pub fn parse_memory_section(
for entry in memories {
let memory = entry.map_err(to_wasm_error)?;
environ.declare_memory(MemoryType {
minimum: Pages(memory.limits.initial),
maximum: memory.limits.maximum.map(Pages),
shared: memory.shared,
})?;
match memory {
WPMemoryType::M32 { limits, shared } => {
environ.declare_memory(MemoryType {
minimum: Pages(limits.initial),
maximum: limits.maximum.map(Pages),
shared: shared,
})?;
}
WPMemoryType::M64 { .. } => unimplemented!("64bit memory not implemented yet"),
}
}
Ok(())
@@ -281,6 +295,9 @@ pub fn parse_export_section<'data>(
ExternalKind::Global => {
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(())
}
/// 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.
pub fn parse_data_section<'data>(
data: DataSectionReader<'data>,

View File

@@ -1,4 +1,3 @@
use crate::sourceloc::SourceLoc;
use crate::CodeOffset;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
@@ -10,8 +9,6 @@ use wasmer_vm::TrapCode;
pub struct TrapInformation {
/// The offset of the trapping instruction in native code. It is relative to the beginning of the function.
pub code_offset: CodeOffset,
/// Location of trapping instruction in WebAssembly binary module.
pub source_loc: SourceLoc,
/// Code of the trap.
pub trap_code: TrapCode,
}

View File

@@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
dependencies = [
"addr2line",
"cfg-if",
"cfg-if 0.1.10",
"libc",
"miniz_oxide",
"object 0.20.0",
@@ -81,7 +81,7 @@ dependencies = [
"arrayref",
"arrayvec",
"cc",
"cfg-if",
"cfg-if 0.1.10",
"constant_time_eq",
"crypto-mac",
"digest",
@@ -105,6 +105,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.1.0"
@@ -192,7 +198,7 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -213,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
"autocfg",
"cfg-if",
"cfg-if 0.1.10",
"crossbeam-utils",
"lazy_static",
"maybe-uninit",
@@ -227,7 +233,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"crossbeam-utils",
"maybe-uninit",
]
@@ -239,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"cfg-if",
"cfg-if 0.1.10",
"lazy_static",
]
@@ -379,7 +385,7 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"wasi",
]
@@ -481,11 +487,11 @@ dependencies = [
[[package]]
name = "instant"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66"
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@@ -552,7 +558,7 @@ version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -668,7 +674,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"cloudabi",
"instant",
"libc",
@@ -1015,7 +1021,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"rand",
"redox_syscall",
@@ -1058,7 +1064,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"tracing-attributes",
"tracing-core",
]
@@ -1111,7 +1117,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
name = "wasmer"
version = "1.0.0-alpha4"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"indexmap",
"more-asserts",
"target-lexicon",
@@ -1245,7 +1251,7 @@ name = "wasmer-engine-jit"
version = "1.0.0-alpha4"
dependencies = [
"bincode",
"cfg-if",
"cfg-if 0.1.10",
"region",
"serde",
"serde_bytes",
@@ -1261,7 +1267,7 @@ name = "wasmer-engine-native"
version = "1.0.0-alpha4"
dependencies = [
"bincode",
"cfg-if",
"cfg-if 0.1.10",
"leb128",
"libloading",
"serde",
@@ -1317,7 +1323,7 @@ version = "1.0.0-alpha4"
dependencies = [
"backtrace",
"cc",
"cfg-if",
"cfg-if 0.1.10",
"indexmap",
"libc",
"memoffset",

View File

@@ -14,16 +14,16 @@ edition = "2018"
maintenance = { status = "deprecated" }
[dependencies]
wasmer-types = { path = "../../wasmer-types", version = "1.0.0-alpha4" }
wasmer = { path = "../../api", version = "1.0.0-alpha4" }
wasmer-cache = { path = "../../cache", version = "1.0.0-alpha4" }
wasmer-compiler = { path = "../../compiler", version = "1.0.0-alpha4", features = ["translator"] }
wasmer-compiler-llvm = { path = "../../compiler-llvm", version = "1.0.0-alpha4", optional = true }
wasmer-compiler-cranelift = { path = "../../compiler-cranelift", version = "1.0.0-alpha4", optional = true }
wasmer-compiler-singlepass = { path = "../../compiler-singlepass", version = "1.0.0-alpha4", optional = true }
wasmer-engine = { path = "../../engine", version = "1.0.0-alpha4" }
wasmer-engine-jit = { path = "../../engine-jit", version = "1.0.0-alpha4" }
wasmer-vm = { path = "../../vm", version = "1.0.0-alpha4" }
wasmer-types = { path = "../../wasmer-types", version = "1.0.0-alpha5" }
wasmer = { path = "../../api", version = "1.0.0-alpha5" }
wasmer-cache = { path = "../../cache", version = "1.0.0-alpha5" }
wasmer-compiler = { path = "../../compiler", version = "1.0.0-alpha5", features = ["translator"] }
wasmer-compiler-llvm = { path = "../../compiler-llvm", version = "1.0.0-alpha5", 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-alpha5", optional = true }
wasmer-engine = { path = "../../engine", version = "1.0.0-alpha5" }
wasmer-engine-jit = { path = "../../engine-jit", version = "1.0.0-alpha5" }
wasmer-vm = { path = "../../vm", version = "1.0.0-alpha5" }
lazy_static = "1.4"
[build-dependencies]

View File

@@ -102,14 +102,14 @@ impl Module {
// Properly drop the empty `vm::Ctx`
// created by the host function.
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`,
// which is actually a `vm::Ctx`
// pointer, to fallback on the
// environment hack.
function.vmctx = pre_instance.vmctx_ptr() as _;
function.vmctx.host_env = pre_instance.vmctx_ptr() as _;
}
// `function` is a dynamic host function
// constructed with
@@ -147,13 +147,13 @@ impl Module {
new::wasmer_vm::VMDynamicFunctionContext<
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.
vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx();
// … without anyone noticing…
function.vmctx = Box::into_raw(vmctx) as _;
function.vmctx.host_env = Box::into_raw(vmctx) as _;
}
}

View File

@@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
dependencies = [
"addr2line",
"cfg-if",
"cfg-if 0.1.10",
"libc",
"miniz_oxide",
"object 0.20.0",
@@ -81,7 +81,7 @@ dependencies = [
"arrayref",
"arrayvec",
"cc",
"cfg-if",
"cfg-if 0.1.10",
"constant_time_eq",
"crypto-mac",
"digest",
@@ -105,6 +105,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.1.0"
@@ -192,7 +198,7 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -213,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
"autocfg",
"cfg-if",
"cfg-if 0.1.10",
"crossbeam-utils",
"lazy_static",
"maybe-uninit",
@@ -227,7 +233,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"crossbeam-utils",
"maybe-uninit",
]
@@ -239,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"cfg-if",
"cfg-if 0.1.10",
"lazy_static",
]
@@ -379,7 +385,7 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"wasi",
]
@@ -481,11 +487,11 @@ dependencies = [
[[package]]
name = "instant"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66"
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@@ -552,7 +558,7 @@ version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -668,7 +674,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"cloudabi",
"instant",
"libc",
@@ -1015,7 +1021,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"rand",
"redox_syscall",
@@ -1058,7 +1064,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"tracing-attributes",
"tracing-core",
]
@@ -1111,7 +1117,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
name = "wasmer"
version = "1.0.0-alpha4"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"indexmap",
"more-asserts",
"target-lexicon",
@@ -1234,7 +1240,7 @@ name = "wasmer-engine-jit"
version = "1.0.0-alpha4"
dependencies = [
"bincode",
"cfg-if",
"cfg-if 0.1.10",
"region",
"serde",
"serde_bytes",
@@ -1250,7 +1256,7 @@ name = "wasmer-engine-native"
version = "1.0.0-alpha4"
dependencies = [
"bincode",
"cfg-if",
"cfg-if 0.1.10",
"leb128",
"libloading",
"serde",
@@ -1313,7 +1319,7 @@ version = "1.0.0-alpha4"
dependencies = [
"backtrace",
"cc",
"cfg-if",
"cfg-if 0.1.10",
"indexmap",
"libc",
"memoffset",

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-emscripten"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Emscripten implementation library for Wasmer WebAssembly runtime"
categories = ["wasm", "os"]
keywords = ["wasm", "webassembly", "abi", "emscripten", "posix"]
@@ -13,10 +13,10 @@ edition = "2018"
[dependencies]
byteorder = "1.3"
lazy_static = "1.4"
libc = "^0.2.69"
libc = "^0.2"
log = "0.4"
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]
getrandom = "0.1"
getrandom = "0.2"

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-engine-jit"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer JIT Engine"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "engine", "jit"]
@@ -11,10 +11,10 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", features = ["translator"] }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = ["translator"] }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
region = "2.2"
serde = { version = "1.0", features = ["derive", "rc"] }

View File

@@ -11,7 +11,8 @@ use wasmer_compiler::{CompileError, Features, Triple};
#[cfg(feature = "compiler")]
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment};
use wasmer_engine::{
register_frame_info, Artifact, DeserializeError, GlobalFrameInfoRegistration, SerializeError,
register_frame_info, Artifact, DeserializeError, FunctionExtent, GlobalFrameInfoRegistration,
SerializeError,
};
#[cfg(feature = "compiler")]
use wasmer_engine::{Engine, SerializableFunctionFrameInfo, Tunables};
@@ -32,6 +33,7 @@ pub struct JITArtifact {
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
}
impl JITArtifact {
@@ -203,7 +205,16 @@ impl JITArtifact {
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 =
finished_function_call_trampolines.into_boxed_slice();
let finished_dynamic_function_trampolines =
@@ -217,6 +228,7 @@ impl JITArtifact {
finished_dynamic_function_trampolines,
signatures,
frame_info_registration: Mutex::new(None),
finished_function_lengths,
})
}
@@ -247,11 +259,19 @@ impl Artifact for JITArtifact {
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 finished_functions = &self.finished_functions;
*info = register_frame_info(
self.serializable.compile_info.module.clone(),
finished_functions,
&finished_function_extents,
frame_infos.clone(),
);
}
@@ -280,7 +300,6 @@ impl Artifact for JITArtifact {
&self.finished_function_call_trampolines
}
// TODO: return *const instead of *mut
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
&self.finished_dynamic_function_trampolines
}

View File

@@ -7,7 +7,7 @@ use wasmer_compiler::Compiler;
use wasmer_compiler::{
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::Features;
use wasmer_types::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex};
@@ -193,7 +193,7 @@ impl JITEngineInner {
custom_sections: &PrimaryMap<SectionIndex, CustomSection>,
) -> Result<
(
PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>,
PrimaryMap<LocalFunctionIndex, FunctionExtent>,
PrimaryMap<SignatureIndex, VMTrampoline>,
PrimaryMap<FunctionIndex, FunctionBodyPtr>,
PrimaryMap<SectionIndex, SectionBodyPtr>,
@@ -228,7 +228,10 @@ impl JITEngineInner {
let allocated_functions_result = allocated_functions
.drain(0..functions.len())
.map(|slice| FunctionBodyPtr(slice as *mut [_]))
.map(|slice| FunctionExtent {
ptr: FunctionBodyPtr(slice.as_ptr()),
length: slice.len(),
})
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
@@ -244,7 +247,7 @@ impl JITEngineInner {
let allocated_dynamic_function_trampolines = allocated_functions
.drain(..)
.map(|slice| FunctionBodyPtr(slice as *mut [_]))
.map(|slice| FunctionBodyPtr(slice.as_ptr()))
.collect::<PrimaryMap<FunctionIndex, _>>();
let mut exec_iter = allocated_executable_sections.iter();

View File

@@ -5,23 +5,21 @@ use wasmer_compiler::{
JumpTable, JumpTableOffsets, Relocation, RelocationKind, RelocationTarget, Relocations,
SectionIndex,
};
use wasmer_engine::FunctionExtent;
use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::LocalFunctionIndex;
use wasmer_vm::ModuleInfo;
use wasmer_vm::{FunctionBodyPtr, SectionBodyPtr, VMFunctionBody};
use wasmer_vm::SectionBodyPtr;
fn apply_relocation(
body: usize,
r: &Relocation,
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>,
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
jt_offsets: &PrimaryMap<LocalFunctionIndex, JumpTableOffsets>,
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
) {
let target_func_address: usize = match r.reloc_target {
RelocationTarget::LocalFunc(index) => {
let fatptr: *const [VMFunctionBody] = allocated_functions[index].0;
fatptr as *const VMFunctionBody as usize
}
RelocationTarget::LocalFunc(index) => *allocated_functions[index].ptr as usize,
RelocationTarget::LibCall(libcall) => libcall.function_pointer(),
RelocationTarget::CustomSection(custom_section) => {
*allocated_sections[custom_section] as usize
@@ -31,8 +29,7 @@ fn apply_relocation(
.get(func_index)
.and_then(|ofs| ofs.get(JumpTable::new(jt.index())))
.expect("func jump table");
let fatptr: *const [VMFunctionBody] = allocated_functions[func_index].0;
fatptr as *const VMFunctionBody as usize + offset as usize
*allocated_functions[func_index].ptr as usize + offset as usize
}
};
@@ -69,7 +66,7 @@ fn apply_relocation(
/// required relocations and jump tables.
pub fn link_module(
_module: &ModuleInfo,
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>,
allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
jt_offsets: &PrimaryMap<LocalFunctionIndex, JumpTableOffsets>,
function_relocations: Relocations,
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
@@ -81,9 +78,8 @@ pub fn link_module(
apply_relocation(body, r, allocated_functions, jt_offsets, allocated_sections);
}
}
for (i, function_relocs) in function_relocations.into_iter() {
let fatptr: *const [VMFunctionBody] = allocated_functions[i].0;
let body = fatptr as *const VMFunctionBody as usize;
for (i, function_relocs) in function_relocations.iter() {
let body = *allocated_functions[i].ptr as usize;
for r in function_relocs {
apply_relocation(body, r, allocated_functions, jt_offsets, allocated_sections);
}

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-engine-native"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer Native Engine"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "engine", "native"]
@@ -11,11 +11,11 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
wasmer-object = { path = "../object", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
wasmer-object = { path = "../object", version = "1.0.0-alpha5" }
serde = { version = "1.0", features = ["derive", "rc"] }
cfg-if = "0.1"
tracing = "0.1"

View File

@@ -347,7 +347,7 @@ impl NativeArtifact {
) -> Result<Self, CompileError> {
let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
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 =
metadata.symbol_to_name(Symbol::LocalFunction(function_local_index));
unsafe {
@@ -356,14 +356,9 @@ impl NativeArtifact {
let func: LibrarySymbol<unsafe extern "C" fn()> = lib
.get(function_name.as_bytes())
.map_err(to_compile_error)?;
let raw = *func.into_raw();
// The function pointer is a fat pointer, however this information
// 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));
finished_functions.push(FunctionBodyPtr(
func.into_raw().into_raw() as *const VMFunctionBody
));
}
}
@@ -397,11 +392,9 @@ impl NativeArtifact {
let trampoline: LibrarySymbol<unsafe extern "C" fn()> = lib
.get(function_name.as_bytes())
.map_err(to_compile_error)?;
let raw = *trampoline.into_raw();
let trampoline_pointer = std::slice::from_raw_parts(raw as *const (), 0);
let trampoline_pointer =
trampoline_pointer as *const [()] as *mut [VMFunctionBody];
finished_dynamic_function_trampolines.push(FunctionBodyPtr(trampoline_pointer));
finished_dynamic_function_trampolines.push(FunctionBodyPtr(
trampoline.into_raw().into_raw() as *const VMFunctionBody,
));
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-engine-object-file"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
description = "Wasmer Object File Engine"
categories = ["wasm"]
@@ -11,11 +11,11 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha01.0" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" }
wasmer-object = { path = "../object", version = "1.0.0-alpha4" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
wasmer-object = { path = "../object", version = "1.0.0-alpha5" }
serde = { version = "1.0", features = ["derive", "rc"] }
cfg-if = "0.1"
tracing = "0.1"

View File

@@ -306,12 +306,6 @@ impl ObjectFileArtifact {
let num_finished_functions = usize::from_ne_bytes(byte_buffer);
let mut finished_functions = PrimaryMap::new();
#[repr(C)]
struct SlicePtr {
ptr: usize,
len: usize,
}
let engine_inner = engine.inner();
let signature_registry = engine_inner.signatures();
let mut sig_map: BTreeMap<SignatureIndex, VMSharedSignatureIndex> = BTreeMap::new();
@@ -323,14 +317,13 @@ impl ObjectFileArtifact {
let vm_shared_idx = signature_registry.register(&func_type);
sig_map.insert(sig_idx, vm_shared_idx);
let mut sp = SlicePtr { ptr: 0, len: 0 };
byte_buffer[0..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;
// 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);
}
@@ -364,14 +357,12 @@ impl ObjectFileArtifact {
cur_offset += WORD_SIZE;
let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
for _i in 0..num_dynamic_trampoline_functions {
let mut sp = SlicePtr { ptr: 0, len: 0 };
byte_buffer[0..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;
// 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_dynamic_function_trampolines.push(fp);
}

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-engine"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer Engine abstraction"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "engine"]
@@ -11,10 +11,10 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha4" }
target-lexicon = { version = "0.10", default-features = false }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
target-lexicon = { version = "0.11", default-features = false }
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
backtrace = "0.3"
rustc-demangle = "0.1"

View File

@@ -170,7 +170,7 @@ pub fn resolve_imports(
};
function_imports.push(VMFunctionImport {
body: address,
vmctx: f.vmctx,
environment: f.vmctx,
});
host_function_env_initializers.push(f.function_ptr);

View File

@@ -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.
///
/// 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.
pub fn register(
module: Arc<ModuleInfo>,
finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionExtent>,
frame_infos: PrimaryMap<LocalFunctionIndex, SerializableFunctionFrameInfo>,
) -> Option<GlobalFrameInfoRegistration> {
let mut min = usize::max_value();
let mut max = 0;
let mut functions = BTreeMap::new();
for (i, allocated) in finished_functions.iter() {
let (start, end) = unsafe {
let ptr = (***allocated).as_ptr();
let len = (***allocated).len();
(ptr as usize, ptr as usize + len)
};
for (
i,
FunctionExtent {
ptr: start,
length: len,
},
) in finished_functions.iter()
{
let start = **start as usize;
let end = start + len;
min = cmp::min(min, start);
max = cmp::max(max, end);
let func = FunctionInfo {

View File

@@ -2,5 +2,6 @@ mod error;
mod frame_info;
pub use error::RuntimeError;
pub use frame_info::{
register as register_frame_info, FrameInfo, GlobalFrameInfoRegistration, FRAME_INFO,
register as register_frame_info, FrameInfo, FunctionExtent, GlobalFrameInfoRegistration,
FRAME_INFO,
};

View File

@@ -1,6 +1,6 @@
[package]
name = "wasmer-object"
version = "1.0.0-alpha4"
version = "1.0.0-alpha5"
description = "Wasmer Native Object generator"
categories = ["wasm"]
keywords = ["wasm", "webassembly"]
@@ -11,10 +11,10 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha4" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4", default-features = false, features = [
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", default-features = false, features = [
"std",
"translator"
] }
object = { version = "0.19", default-features = false, features = ["write"] }
object = { version = "0.21", default-features = false, features = ["write"] }
thiserror = "1.0"

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