mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Merge branch 'master' into feature/cache-rework
This commit is contained in:
commit
2234f357b7
@ -12,6 +12,9 @@ environment:
|
||||
ABI: msvc
|
||||
TARGET: x86_64-pc-windows-msvc
|
||||
|
||||
cache:
|
||||
- 'C:\Users\appveyor\.cargo'
|
||||
|
||||
install:
|
||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- rustup-init.exe -yv --default-host %target%
|
||||
@ -27,9 +30,9 @@ test_script:
|
||||
- cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
|
||||
|
||||
before_deploy:
|
||||
- cd installer
|
||||
- cd ./src/installer
|
||||
- iscc wasmer.iss
|
||||
- copy /y .\WasmerInstaller.exe ..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
|
||||
artifacts:
|
||||
|
@ -2,19 +2,19 @@
|
||||
|
||||
Wasmer uses the following components:
|
||||
|
||||
- [Cranelift](https://github.com/cranestation/cranelift): for compiling WASM function binaries into Machine IR
|
||||
- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and also to run WebAssembly spectests
|
||||
- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly Modules
|
||||
- [Cranelift](https://github.com/cranestation/cranelift): for compiling Wasm binaries to machine code
|
||||
- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and running WebAssembly spec tests
|
||||
- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly modules
|
||||
|
||||
## How Wasmer works?
|
||||
## How Wasmer works
|
||||
|
||||
The first time you run `wasmer run myfile.wasm`, wasmer will:
|
||||
The first time you run `wasmer run myfile.wasm`, Wasmer will:
|
||||
|
||||
- Check if is a `.wast` file. If so, transform it to `.wasm`
|
||||
- Check that the provided binary is a valid WebAssembly one. That means, that its binary format starts with `\0asm`.
|
||||
- If it looks like a WebAssembly file, try to parse it with `wasmparser` and generate a `Module` from it
|
||||
- Once a `Module` is generated, an `Instance` is created with the proper `import_object` (that means, if is detected as an emscripten file, it will add the emscripten expected imports)
|
||||
- Try to call the WebAssembly start function, or if unexistent try to search for the one that is exported as `main`.
|
||||
- Check if is a `.wast` file, and if so, transform it to `.wasm`
|
||||
- Check that the provided binary is a valid WebAssembly one, i.e. its binary format starts with `\0asm`.
|
||||
- Parse it with `wasmparser` and generate a `Module` from it
|
||||
- Generate an `Instance` with the proper `import_object` (that means, if is detected to be an Emscripten file, it will add the Emscripten expected imports)
|
||||
- Try to call the WebAssembly `start` function, or if it does not exist, try to search for the function that is exported as `main`
|
||||
|
||||
Find a more detailed explanation of the process below:
|
||||
|
||||
@ -22,7 +22,7 @@ Find a more detailed explanation of the process below:
|
||||
|
||||
As the WebAssembly file is being parsed, it will read the sections in the WebAssembly file (memory, table, function, global and element definitions) using the `Module` (or `ModuleEnvironment`) as the structure to hold this information.
|
||||
|
||||
However, the real IR initialization happens while a function body is being parsed/created. That means, when the parser reads the section `(func ...)`.
|
||||
However, the real IR initialization happens while a function body is being parsed/created, i.e. when the parser reads the section `(func ...)`.
|
||||
While the function body is being parsed the corresponding `FuncEnvironment` methods will be called.
|
||||
|
||||
So for example, if the function is using a table, the `make_table` method within that `FuncEnvironment` will be called.
|
||||
@ -41,15 +41,14 @@ Once we have the compiled values, we will push them to memory and mark them as e
|
||||
|
||||
#### Relocations
|
||||
|
||||
Sometimes the functions that we generated will need to call other functions.
|
||||
However the generated code have no idea how to link this functions together.
|
||||
Sometimes the functions that we generate will need to call other functions, but the generated code has no idea how to link these functions together.
|
||||
|
||||
For example, if a function `A` is calling function `B` (that means is having a `(call b)` on it's body) while compiling `A` we will have no idea where the function `B` lives on memory (as `B` is not yet compiled nor pushed into memory).
|
||||
For example, if a function `A` is calling function `B` (that means is having a `(call b)` on its body) while compiling `A` we will have no idea where the function `B` lives on memory (as `B` is not yet compiled nor pushed into memory).
|
||||
|
||||
For that reason, we will start collecting all the calls that function `A` will need to do under the hood, and save it's offsets.
|
||||
We do that, so we can patch the function calls after compilation, to point to the correct memory address.
|
||||
|
||||
Note: Sometimes this functions rather than living in the same WebAssembly module, they will be provided as import values.
|
||||
Note: sometimes this functions rather than living in the same WebAssembly module, they will be provided as import values.
|
||||
|
||||
#### Traps
|
||||
|
||||
@ -66,5 +65,5 @@ Once that's finished, we will have a `Instance` function that will be ready to e
|
||||
|
||||
## Emscripten
|
||||
|
||||
The Wasmer Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs.
|
||||
We provide this integration by filling the `import_object` with the emscripten functions, while instantiating the WebAssembly Instance.
|
||||
Wasmer's Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs.
|
||||
We provide this integration by filling the `import_object` with the Emscripten functions, while instantiating the WebAssembly Instance.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Wasmer is a community effort.
|
||||
In order to build the best WebAssembly runtime it's our duty to see how other runtimes are approaching the same space
|
||||
and get inspired from them on the things that they got right, so wasmer and its community can benefit from a solid
|
||||
and get inspired from them on the things that they got right, so Wasmer and its community can benefit from a solid
|
||||
foundation.
|
||||
|
||||
These are the different project that we used as inspiration:
|
||||
@ -10,9 +10,9 @@ These are the different project that we used as inspiration:
|
||||
- [Nebulet](https://github.com/nebulet/nebulet): as the base for creating a great Rust WebAssembly runtime
|
||||
- [WAVM](https://github.com/wavm/wavm): for their great integration and testing framework
|
||||
- [greenwasm](https://github.com/Kimundi/greenwasm): for their [spectests framework](https://github.com/Kimundi/greenwasm/tree/master/greenwasm-spectest)
|
||||
- [wasmtime](/wasmtime): on their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs).
|
||||
- [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys.
|
||||
- [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility.
|
||||
- [wasmtime](https://github.com/CraneStation/wasmtime): for their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs)
|
||||
- [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys
|
||||
- [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility
|
||||
|
||||
We would love to hear from you if you think we can take inspiration from other projects that we haven't covered here.
|
||||
😊
|
||||
@ -21,10 +21,10 @@ We would love to hear from you if you think we can take inspiration from other p
|
||||
|
||||
### Nebulet
|
||||
|
||||
```
|
||||
```text
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018
|
||||
Copyright (c) 2018
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -47,7 +47,7 @@ SOFTWARE.
|
||||
|
||||
### WAVM
|
||||
|
||||
```
|
||||
```text
|
||||
Copyright (c) 2018, Andrew Scheidecker
|
||||
All rights reserved.
|
||||
|
||||
@ -69,7 +69,7 @@ The contents of [Test/spec](Test/spec) is covered by the license in [Test/spec/L
|
||||
|
||||
### Greenwasm
|
||||
|
||||
```
|
||||
```text
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
@ -275,7 +275,7 @@ limitations under the License.
|
||||
|
||||
### Wasmtime
|
||||
|
||||
```
|
||||
```text
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
@ -497,7 +497,7 @@ Software.
|
||||
```
|
||||
|
||||
### Emscripten
|
||||
```
|
||||
```text
|
||||
Emscripten is available under 2 licenses, the MIT license and the
|
||||
University of Illinois/NCSA Open Source License.
|
||||
|
||||
@ -557,7 +557,7 @@ the following conditions:
|
||||
Neither the names of Mozilla,
|
||||
nor the names of its contributors may be used to endorse
|
||||
or promote products derived from this Software without specific prior
|
||||
written permission.
|
||||
written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
|
61
Cargo.lock
generated
61
Cargo.lock
generated
@ -113,6 +113,21 @@ name = "cast"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.28"
|
||||
@ -713,6 +728,14 @@ dependencies = [
|
||||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.13"
|
||||
@ -753,6 +776,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "serde"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-bench"
|
||||
@ -881,6 +907,19 @@ dependencies = [
|
||||
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.0.4"
|
||||
@ -925,6 +964,14 @@ dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.10.0"
|
||||
@ -1058,6 +1105,16 @@ dependencies = [
|
||||
"wasmer-runtime-core 0.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-runtime-c-api"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-runtime 0.1.4",
|
||||
"wasmer-runtime-core 0.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-runtime-core"
|
||||
version = "0.1.2"
|
||||
@ -1183,6 +1240,7 @@ dependencies = [
|
||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||
"checksum cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32e01024aaf5390d6a8145047371a4f5b0063a14c1e411bc731353bd2278ca44"
|
||||
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
|
||||
"checksum cexpr 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "644d693ecfa91955ed32dcc7eda4914e1be97a641fb6f0645a37348e20b230da"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
@ -1255,6 +1313,7 @@ dependencies = [
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
|
||||
"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
|
||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
@ -1276,11 +1335,13 @@ dependencies = [
|
||||
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
||||
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||
"checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9"
|
||||
"checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff"
|
||||
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
|
||||
|
@ -27,7 +27,7 @@ wasmer-runtime-core = { path = "lib/runtime-core" }
|
||||
wasmer-emscripten = { path = "lib/emscripten" }
|
||||
|
||||
[workspace]
|
||||
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler"]
|
||||
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api"]
|
||||
|
||||
[build-dependencies]
|
||||
wabt = "0.7.2"
|
||||
|
4
LICENSE
4
LICENSE
@ -1,6 +1,4 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-Present Syrus Akbary
|
||||
Copyright (c) 2019 Syrus Akbary
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
8
Makefile
8
Makefile
@ -12,6 +12,9 @@ spectests:
|
||||
emtests:
|
||||
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten
|
||||
|
||||
capi:
|
||||
WASM_EMSCRIPTEN_GENERATE_C_API_HEADERS=1 cargo build --manifest-path lib/runtime-c-api/Cargo.toml --features generate-c-api-headers
|
||||
|
||||
# clean:
|
||||
# rm -rf artifacts
|
||||
|
||||
@ -34,9 +37,10 @@ precommit: lint test
|
||||
|
||||
test:
|
||||
# We use one thread so the emscripten stdouts doesn't collide
|
||||
cargo test --all -- --test-threads=1 $(runargs)
|
||||
cargo test --all --exclude wasmer-runtime-c-api -- --test-threads=1 $(runargs)
|
||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
||||
# cargo test -p wasmer-spectests -- --test-threads=1 $(runargs)
|
||||
cargo build -p wasmer-runtime-c-api
|
||||
cargo test -p wasmer-runtime-c-api -- --nocapture
|
||||
|
||||
release:
|
||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||
|
64
README.md
64
README.md
@ -1,16 +1,24 @@
|
||||
<p align="center"><a href="https://wasmer.io" target="_blank" rel="noopener noreferrer"><img width="400" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo"></a></p>
|
||||
<p align="center">
|
||||
<a href="https://wasmer.io" target="_blank" rel="noopener noreferrer">
|
||||
<img width="400" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/wasmerio/wasmer/"><img src="https://img.shields.io/circleci/project/github/wasmerio/wasmer/master.svg" alt="Build Status"></a>
|
||||
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE"><img src="https://img.shields.io/github/license/wasmerio/wasmer.svg" alt="License"></a>
|
||||
<a href="https://circleci.com/gh/wasmerio/wasmer/">
|
||||
<img src="https://img.shields.io/circleci/project/github/wasmerio/wasmer/master.svg" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/wasmerio/wasmer.svg" alt="License">
|
||||
</a>
|
||||
<a href="https://spectrum.chat/wasmer">
|
||||
<img alt="Join the Wasmer Community" src="https://withspectrum.github.io/badge/badge.svg" />
|
||||
<img src="https://withspectrum.github.io/badge/badge.svg" alt="Join the Wasmer Community">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Introduction
|
||||
|
||||
[Wasmer](https://wasmer.io/) is a Standalone JIT WebAssembly runtime, aiming to be fully compatible with Emscripten, Rust and Go.
|
||||
[Wasmer](https://wasmer.io/) is a standalone JIT WebAssembly runtime, aiming to be fully compatible with Emscripten, Rust and Go.
|
||||
|
||||
Install Wasmer with:
|
||||
|
||||
@ -18,20 +26,20 @@ Install Wasmer with:
|
||||
curl https://get.wasmer.io -sSfL | sh
|
||||
```
|
||||
|
||||
_**NEW ✨**: Now you can also embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how to do it!_
|
||||
_**NEW ✨**: You can now embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how!_
|
||||
|
||||
### Usage
|
||||
|
||||
`wasmer` can execute both the standard binary format (`.wasm`) and the text
|
||||
Wasmer can execute both the standard binary format (`.wasm`) and the text
|
||||
format defined by the WebAssembly reference interpreter (`.wat`).
|
||||
|
||||
Once installed, you will be able to run any WebAssembly files (_including Nginx, and Lua!_):
|
||||
Once installed, you will be able to run any WebAssembly files (_including nginx and Lua!_):
|
||||
|
||||
```sh
|
||||
# Run Lua
|
||||
wasmer run examples/lua.wasm
|
||||
|
||||
# Run Nginx
|
||||
# Run nginx
|
||||
wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
|
||||
```
|
||||
|
||||
@ -39,13 +47,13 @@ wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
|
||||
|
||||
Wasmer is structured into different directories:
|
||||
|
||||
- [`src`](./src): code related to the wasmer excutable binary itself
|
||||
- [`src`](./src): code related to the Wasmer executable itself
|
||||
- [`lib`](./lib): modularized libraries that Wasmer uses under the hood
|
||||
- [`examples`](./examples): some useful examples to getting started with wasmer
|
||||
- [`examples`](./examples): some useful examples to getting started with Wasmer
|
||||
|
||||
## Dependencies
|
||||
|
||||
Building wasmer requires [rustup](https://rustup.rs/).
|
||||
Building Wasmer requires [rustup](https://rustup.rs/).
|
||||
|
||||
To build on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/)
|
||||
then follow the onscreen instructions.
|
||||
@ -66,13 +74,13 @@ Please select your operating system:
|
||||
|
||||
#### macOS
|
||||
|
||||
If you have [homebrew](https://brew.sh/) installed:
|
||||
If you have [Homebrew](https://brew.sh/) installed:
|
||||
|
||||
```sh
|
||||
brew install cmake
|
||||
```
|
||||
|
||||
Or, in case you have [ports](https://www.macports.org/install.php):
|
||||
Or, in case you have [MacPorts](https://www.macports.org/install.php):
|
||||
|
||||
```sh
|
||||
sudo port install cmake
|
||||
@ -86,16 +94,16 @@ sudo apt install cmake
|
||||
|
||||
#### Windows (MSVC)
|
||||
|
||||
Windows support is _highly experimental_. Only simple wasm programs may be run, and no syscalls are allowed. This means
|
||||
nginx and lua do not work on Windows. See [this issue for ongoing Emscripten syscall polyfills for Windows](https://github.com/wasmerio/wasmer/pull/176).
|
||||
Windows support is _highly experimental_. Only simple Wasm programs may be run, and no syscalls are allowed. This means
|
||||
nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmerio/wasmer/issues/176) regarding Emscripten syscall polyfills for Windows.
|
||||
|
||||
1. Install Python for Windows (https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine.
|
||||
You should change the installation to install the "Add python.exe to Path" feature.
|
||||
1. Install [Python for Windows](https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine.
|
||||
Make sure to enable "Add python.exe to Path" during installation.
|
||||
|
||||
2. Install Git for Windows (https://git-scm.com/download/win). DO allow it to add git.exe to the PATH (default
|
||||
2. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default
|
||||
settings for the installer are fine).
|
||||
|
||||
3. Install CMake (https://cmake.org/download/). Ensure CMake is in the PATH.
|
||||
3. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH.
|
||||
|
||||
## Building
|
||||
|
||||
@ -113,7 +121,7 @@ cargo install --path .
|
||||
|
||||
## Testing
|
||||
|
||||
Thanks to [spectests](https://github.com/wasmerio/wasmer/tree/master/lib/runtime-core/spectests) we can assure 100% compatibility with the WebAssembly spec test suite.
|
||||
Thanks to [spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) we can ensure 100% compatibility with the WebAssembly spec test suite.
|
||||
|
||||
Tests can be run with:
|
||||
|
||||
@ -121,7 +129,7 @@ Tests can be run with:
|
||||
make test
|
||||
```
|
||||
|
||||
If you need to re-generate the Rust tests from the spectests
|
||||
If you need to regenerate the Rust tests from the spec tests
|
||||
you can run:
|
||||
|
||||
```sh
|
||||
@ -138,20 +146,20 @@ make integration-tests
|
||||
|
||||
Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction.
|
||||
|
||||
Below are some of the goals (written with order) of this project:
|
||||
Below are some of the goals of this project (in order of priority):
|
||||
|
||||
- [x] It should be 100% compatible with the [WebAssembly Spectest](https://github.com/wasmerio/wasmer/tree/master/spectests)
|
||||
- [x] It should be 100% compatible with the [WebAssembly spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests)
|
||||
- [x] It should be fast _(partially achieved)_
|
||||
- [ ] Support Emscripten calls _(in the works)_
|
||||
- [ ] Support Rust ABI calls
|
||||
- [ ] Support GO ABI calls
|
||||
- [ ] Support Go ABI calls
|
||||
|
||||
## Architecture
|
||||
|
||||
If you would like to know how Wasmer works under the hood, please visit our [ARCHITECTURE](https://github.com/wasmerio/wasmer/blob/master/ARCHITECTURE.md) document.
|
||||
If you would like to know how Wasmer works under the hood, please see [ARCHITECTURE.md](./ARCHITECTURE.md).
|
||||
|
||||
## License
|
||||
|
||||
MIT/Apache-2.0
|
||||
Wasmer is primarily distributed under the terms of the [MIT license](http://opensource.org/licenses/MIT) ([LICENSE](./LICENSE)).
|
||||
|
||||
<small>[Attributions](./ATTRIBUTIONS.md)</small>.
|
||||
[ATTRIBUTIONS](./ATTRIBUTIONS.md)
|
||||
|
@ -1,8 +1,8 @@
|
||||
# `lua` integration test
|
||||
|
||||
|
||||
This starts wasmer with the lua wasm file. The test asserts on
|
||||
the output of wasmer. Run test with:
|
||||
This starts Wasmer with the Lua Wasm file. The test makes assertions on
|
||||
the output of Wasmer. Run test with:
|
||||
|
||||
```
|
||||
> ./integration_tests/lua/test.sh
|
||||
|
@ -1,11 +1,11 @@
|
||||
# `nginx` integration test
|
||||
|
||||
|
||||
This starts wasmer with the nginx wasm file and serves an html
|
||||
file with some simple text to assert on. The test script does
|
||||
This starts Wasmer with the nginx Wasm file and serves an HTML
|
||||
file with some simple text to assert on. The test script does
|
||||
the assertion.
|
||||
|
||||
Run test with:
|
||||
Run test with:
|
||||
|
||||
```
|
||||
> ./integration_tests/nginx/test.sh
|
||||
|
@ -2,34 +2,34 @@
|
||||
|
||||
Wasmer is modularized into different libraries, separated into three main sections:
|
||||
|
||||
- [Runtime](#Runtime)
|
||||
- [Integrations](#Integrations)
|
||||
- [Backends](#Backends)
|
||||
- [Runtime](#runtime)
|
||||
- [Integrations](#integrations)
|
||||
- [Backends](#backends)
|
||||
|
||||
## Runtime
|
||||
|
||||
The core of Wasmer is the runtime, which provides the necessary
|
||||
abstractions to create a good user-experience when embedding.
|
||||
abstractions to create a good user experience when embedding.
|
||||
|
||||
The runtime is divided into two main libraries:
|
||||
|
||||
- [runtime-core](./runtime-core/): The main implementation of the runtime.
|
||||
- [runtime](./runtime/): Easy-to-use api on top of runtime-core.
|
||||
- [runtime](./runtime/): Easy-to-use API on top of `runtime-core`.
|
||||
|
||||
## Integrations
|
||||
|
||||
The intergration run on-top of the Wasmer runtime and allow us to run WebAssembly files compiled for different environments.
|
||||
The integration builds on the Wasmer runtime and allow us to run WebAssembly files compiled for different environments.
|
||||
|
||||
Wasmer intends to support different integrations:
|
||||
|
||||
- [emscripten](./emscripten): run emscripten-generated WebAssembly files, such as [Lua](../examples/lua.wasm) or [Nginx](../examples/nginx/nginx.wasm).
|
||||
- [emscripten](./emscripten): run Emscripten-generated WebAssembly files, such as [Lua](../examples/lua.wasm) or [nginx](../examples/nginx/nginx.wasm).
|
||||
- Go ABI: _we will work on this soon! Want to give us a hand? ✋_
|
||||
- Blazor: _researching period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_
|
||||
- Blazor: _research period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_
|
||||
|
||||
## Backends
|
||||
|
||||
The Wasmer [runtime](./runtime) is designed to support multiple compiler backends, allowing the user
|
||||
to tune the codegen properties (compile speed, performance, etc) to fit your usecase best.
|
||||
to tune the codegen properties (compile speed, performance, etc) to best fit their use case.
|
||||
|
||||
Currently, we support a Cranelift compiler backend:
|
||||
|
||||
|
175
lib/emscripten/src/emscripten_target.rs
Normal file
175
lib/emscripten/src/emscripten_target.rs
Normal file
@ -0,0 +1,175 @@
|
||||
use crate::env::get_emscripten_data;
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
|
||||
pub fn setTempRet0(ctx: &mut Ctx, a: i32) {
|
||||
debug!("emscripten::setTempRet0");
|
||||
}
|
||||
pub fn getTempRet0(ctx: &mut Ctx) -> i32 {
|
||||
debug!("emscripten::getTempRet0");
|
||||
0
|
||||
}
|
||||
pub fn nullFunc_ji(ctx: &mut Ctx, a: i32) {
|
||||
debug!("emscripten::nullFunc_ji");
|
||||
}
|
||||
pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 {
|
||||
debug!("emscripten::invoke_i");
|
||||
if let Some(dyn_call_i) = &get_emscripten_data(ctx).dyn_call_i {
|
||||
dyn_call_i.call(index).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_i is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
|
||||
debug!("emscripten::invoke_ii");
|
||||
if let Some(dyn_call_ii) = &get_emscripten_data(ctx).dyn_call_ii {
|
||||
dyn_call_ii.call(index, a1).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_ii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iii");
|
||||
if let Some(dyn_call_iii) = &get_emscripten_data(ctx).dyn_call_iii {
|
||||
dyn_call_iii.call(index, a1, a2).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iiii");
|
||||
if let Some(dyn_call_iiii) = &get_emscripten_data(ctx).dyn_call_iiii {
|
||||
dyn_call_iiii.call(index, a1, a2, a3).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_v(ctx: &mut Ctx, index: i32) {
|
||||
debug!("emscripten::invoke_v");
|
||||
if let Some(dyn_call_v) = &get_emscripten_data(ctx).dyn_call_v {
|
||||
dyn_call_v.call(index).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_v is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) {
|
||||
debug!("emscripten::invoke_vi");
|
||||
if let Some(dyn_call_vi) = &get_emscripten_data(ctx).dyn_call_vi {
|
||||
dyn_call_vi.call(index, a1).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_vi is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
|
||||
debug!("emscripten::invoke_vii");
|
||||
if let Some(dyn_call_vii) = &get_emscripten_data(ctx).dyn_call_vii {
|
||||
dyn_call_vii.call(index, a1, a2).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_vii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
|
||||
debug!("emscripten::invoke_viii");
|
||||
if let Some(dyn_call_viii) = &get_emscripten_data(ctx).dyn_call_viii {
|
||||
dyn_call_viii.call(index, a1, a2, a3).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
|
||||
debug!("emscripten::invoke_viiii");
|
||||
if let Some(dyn_call_viiii) = &get_emscripten_data(ctx).dyn_call_viiii {
|
||||
dyn_call_viiii.call(index, a1, a2, a3, a4).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn __Unwind_Backtrace(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::__Unwind_Backtrace");
|
||||
0
|
||||
}
|
||||
pub fn __Unwind_FindEnclosingFunction(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::__Unwind_FindEnclosingFunction");
|
||||
0
|
||||
}
|
||||
pub fn __Unwind_GetIPInfo(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::__Unwind_GetIPInfo");
|
||||
0
|
||||
}
|
||||
pub fn ___cxa_find_matching_catch_2(ctx: &mut Ctx) -> i32 {
|
||||
debug!("emscripten::___cxa_find_matching_catch_2");
|
||||
0
|
||||
}
|
||||
pub fn ___cxa_find_matching_catch_3(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::___cxa_find_matching_catch_3");
|
||||
0
|
||||
}
|
||||
pub fn ___cxa_free_exception(ctx: &mut Ctx, a: i32) {
|
||||
debug!("emscripten::___cxa_free_exception");
|
||||
}
|
||||
pub fn ___resumeException(ctx: &mut Ctx, a: i32) {
|
||||
debug!("emscripten::___resumeException");
|
||||
}
|
||||
pub fn _dladdr(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::_dladdr");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_cond_destroy(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_cond_destroy");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_cond_init(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_cond_init");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_cond_signal(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_cond_signal");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_cond_wait(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_cond_wait");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_condattr_destroy(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_condattr_destroy");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_condattr_init(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_condattr_init");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_condattr_setclock(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_condattr_setclock");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_mutex_destroy(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_mutex_destroy");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_mutex_init(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_mutex_init");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_mutexattr_destroy(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_mutexattr_destroy");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_mutexattr_init(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_mutexattr_init");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_mutexattr_settype(ctx: &mut Ctx, a: i32, b: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_mutexattr_settype");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_rwlock_rdlock(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_rwlock_rdlock");
|
||||
0
|
||||
}
|
||||
pub fn _pthread_rwlock_unlock(ctx: &mut Ctx, a: i32) -> i32 {
|
||||
debug!("emscripten::_pthread_rwlock_unlock");
|
||||
0
|
||||
}
|
||||
pub fn ___gxx_personality_v0(ctx: &mut Ctx, a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) -> i32 {
|
||||
debug!("emscripten::___gxx_personality_v0");
|
||||
0
|
||||
}
|
@ -27,6 +27,7 @@ mod file_descriptor;
|
||||
pub mod stdio;
|
||||
|
||||
// EMSCRIPTEN APIS
|
||||
mod emscripten_target;
|
||||
mod env;
|
||||
mod errno;
|
||||
mod exception;
|
||||
@ -92,8 +93,17 @@ pub struct EmscriptenData<'a> {
|
||||
pub memalign: Option<Func<'a, (u32, u32), u32>>,
|
||||
pub memset: Func<'a, (u32, u32, u32), u32>,
|
||||
pub stack_alloc: Func<'a, u32, u32>,
|
||||
|
||||
pub jumps: Vec<UnsafeCell<[u32; 27]>>,
|
||||
|
||||
pub dyn_call_i: Option<Func<'a, i32, i32>>,
|
||||
pub dyn_call_ii: Option<Func<'a, (i32, i32), i32>>,
|
||||
pub dyn_call_iii: Option<Func<'a, (i32, i32, i32), i32>>,
|
||||
pub dyn_call_iiii: Option<Func<'a, (i32, i32, i32, i32), i32>>,
|
||||
pub dyn_call_v: Option<Func<'a, (i32)>>,
|
||||
pub dyn_call_vi: Option<Func<'a, (i32, i32)>>,
|
||||
pub dyn_call_vii: Option<Func<'a, (i32, i32, i32)>>,
|
||||
pub dyn_call_viii: Option<Func<'a, (i32, i32, i32, i32)>>,
|
||||
pub dyn_call_viiii: Option<Func<'a, (i32, i32, i32, i32, i32)>>,
|
||||
}
|
||||
|
||||
impl<'a> EmscriptenData<'a> {
|
||||
@ -108,6 +118,16 @@ impl<'a> EmscriptenData<'a> {
|
||||
let memset = instance.func("_memset").unwrap();
|
||||
let stack_alloc = instance.func("stackAlloc").unwrap();
|
||||
|
||||
let dyn_call_i = instance.func("dynCall_i").ok();
|
||||
let dyn_call_ii = instance.func("dynCall_ii").ok();
|
||||
let dyn_call_iii = instance.func("dynCall_iii").ok();
|
||||
let dyn_call_iiii = instance.func("dynCall_iiii").ok();
|
||||
let dyn_call_v = instance.func("dynCall_v").ok();
|
||||
let dyn_call_vi = instance.func("dynCall_vi").ok();
|
||||
let dyn_call_vii = instance.func("dynCall_vii").ok();
|
||||
let dyn_call_viii = instance.func("dynCall_viii").ok();
|
||||
let dyn_call_viiii = instance.func("dynCall_viiii").ok();
|
||||
|
||||
EmscriptenData {
|
||||
malloc,
|
||||
free,
|
||||
@ -115,6 +135,15 @@ impl<'a> EmscriptenData<'a> {
|
||||
memset,
|
||||
stack_alloc,
|
||||
jumps: Vec::new(),
|
||||
dyn_call_i,
|
||||
dyn_call_ii,
|
||||
dyn_call_iii,
|
||||
dyn_call_iiii,
|
||||
dyn_call_v,
|
||||
dyn_call_vi,
|
||||
dyn_call_vii,
|
||||
dyn_call_viii,
|
||||
dyn_call_viiii,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -491,6 +520,42 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
||||
"_dlopen" => func!(crate::linking::_dlopen),
|
||||
"_dlsym" => func!(crate::linking::_dlsym),
|
||||
|
||||
// wasm32-unknown-emscripten
|
||||
"setTempRet0" => func!(crate::emscripten_target::setTempRet0),
|
||||
"getTempRet0" => func!(crate::emscripten_target::getTempRet0),
|
||||
"nullFunc_ji" => func!(crate::emscripten_target::nullFunc_ji),
|
||||
"invoke_i" => func!(crate::emscripten_target::invoke_i),
|
||||
"invoke_ii" => func!(crate::emscripten_target::invoke_ii),
|
||||
"invoke_iii" => func!(crate::emscripten_target::invoke_iii),
|
||||
"invoke_iiii" => func!(crate::emscripten_target::invoke_iiii),
|
||||
"invoke_v" => func!(crate::emscripten_target::invoke_v),
|
||||
"invoke_vi" => func!(crate::emscripten_target::invoke_vi),
|
||||
"invoke_vii" => func!(crate::emscripten_target::invoke_vii),
|
||||
"invoke_viii" => func!(crate::emscripten_target::invoke_viii),
|
||||
"invoke_viiii" => func!(crate::emscripten_target::invoke_viiii),
|
||||
"__Unwind_Backtrace" => func!(crate::emscripten_target::__Unwind_Backtrace),
|
||||
"__Unwind_FindEnclosingFunction" => func!(crate::emscripten_target::__Unwind_FindEnclosingFunction),
|
||||
"__Unwind_GetIPInfo" => func!(crate::emscripten_target::__Unwind_GetIPInfo),
|
||||
"___cxa_find_matching_catch_2" => func!(crate::emscripten_target::___cxa_find_matching_catch_2),
|
||||
"___cxa_find_matching_catch_3" => func!(crate::emscripten_target::___cxa_find_matching_catch_3),
|
||||
"___cxa_free_exception" => func!(crate::emscripten_target::___cxa_free_exception),
|
||||
"___resumeException" => func!(crate::emscripten_target::___resumeException),
|
||||
"_dladdr" => func!(crate::emscripten_target::_dladdr),
|
||||
"_pthread_cond_destroy" => func!(crate::emscripten_target::_pthread_cond_destroy),
|
||||
"_pthread_cond_init" => func!(crate::emscripten_target::_pthread_cond_init),
|
||||
"_pthread_cond_signal" => func!(crate::emscripten_target::_pthread_cond_signal),
|
||||
"_pthread_cond_wait" => func!(crate::emscripten_target::_pthread_cond_wait),
|
||||
"_pthread_condattr_destroy" => func!(crate::emscripten_target::_pthread_condattr_destroy),
|
||||
"_pthread_condattr_init" => func!(crate::emscripten_target::_pthread_condattr_init),
|
||||
"_pthread_condattr_setclock" => func!(crate::emscripten_target::_pthread_condattr_setclock),
|
||||
"_pthread_mutex_destroy" => func!(crate::emscripten_target::_pthread_mutex_destroy),
|
||||
"_pthread_mutex_init" => func!(crate::emscripten_target::_pthread_mutex_init),
|
||||
"_pthread_mutexattr_destroy" => func!(crate::emscripten_target::_pthread_mutexattr_destroy),
|
||||
"_pthread_mutexattr_init" => func!(crate::emscripten_target::_pthread_mutexattr_init),
|
||||
"_pthread_mutexattr_settype" => func!(crate::emscripten_target::_pthread_mutexattr_settype),
|
||||
"_pthread_rwlock_rdlock" => func!(crate::emscripten_target::_pthread_rwlock_rdlock),
|
||||
"_pthread_rwlock_unlock" => func!(crate::emscripten_target::_pthread_rwlock_unlock),
|
||||
"___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0),
|
||||
},
|
||||
"global" => {
|
||||
"NaN" => Global::new(Value::F64(f64::NAN)),
|
||||
|
25
lib/runtime-c-api/Cargo.toml
Normal file
25
lib/runtime-c-api/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "wasmer-runtime-c-api"
|
||||
version = "0.1.4"
|
||||
description = "Wasmer c-api library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime = { path = "../runtime", version = "0.1.2" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
||||
libc = "0.2"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = { version = "0.7.1", optional = true }
|
||||
|
||||
[features]
|
||||
generate-c-api-headers = ["cbindgen"]
|
||||
|
||||
|
10
lib/runtime-c-api/README.md
Normal file
10
lib/runtime-c-api/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Wasmer Runtime C API
|
||||
|
||||
## Generating header files
|
||||
Run `make capi` from wasmer project root directory
|
||||
|
||||
## Running tests
|
||||
The tests can be run via `cargo test`, E.g. `cargo test -p wasmer-runtime-c-api -- --nocapture`
|
||||
|
||||
*Running manually*
|
||||
`cmake . && make && make test` from the `lib/runtime-c-api/tests` directory
|
39
lib/runtime-c-api/build.rs
Normal file
39
lib/runtime-c-api/build.rs
Normal file
@ -0,0 +1,39 @@
|
||||
#[cfg(feature = "generate-c-api-headers")]
|
||||
extern crate cbindgen;
|
||||
|
||||
use std::env;
|
||||
|
||||
static CAPI_ENV_VAR: &str = "WASM_EMSCRIPTEN_GENERATE_C_API_HEADERS";
|
||||
|
||||
fn main() {
|
||||
if env::var(CAPI_ENV_VAR).unwrap_or("0".to_string()) == "1" {
|
||||
build();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "generate-c-api-headers")]
|
||||
fn build() {
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
|
||||
use cbindgen::Language;
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir.clone())
|
||||
.with_language(Language::C)
|
||||
.with_include_guard("WASMER_H")
|
||||
.generate()
|
||||
.expect("Unable to generate C bindings")
|
||||
.write_to_file("wasmer.h");
|
||||
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_language(Language::Cxx)
|
||||
.with_include_guard("WASMER_H")
|
||||
.generate()
|
||||
.expect("Unable to generate C++ bindings")
|
||||
.write_to_file("wasmer.hh");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "generate-c-api-headers"))]
|
||||
fn build() {
|
||||
panic!("environment var set to generate wasmer c API headers but generate-c-api-headers feature not enabled")
|
||||
}
|
1105
lib/runtime-c-api/src/lib.rs
Normal file
1105
lib/runtime-c-api/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
20
lib/runtime-c-api/tests/.gitignore
vendored
Normal file
20
lib/runtime-c-api/tests/.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
test-globals
|
||||
test-exports
|
||||
test-instantiate
|
||||
test-import-function
|
||||
test-memory
|
||||
test-module
|
||||
test-tables
|
||||
test-validate
|
||||
rust-build
|
48
lib/runtime-c-api/tests/CMakeLists.txt
Normal file
48
lib/runtime-c-api/tests/CMakeLists.txt
Normal file
@ -0,0 +1,48 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (WasmerCApiTests)
|
||||
|
||||
add_executable(test-exports test-exports.c)
|
||||
add_executable(test-globals test-globals.c)
|
||||
add_executable(test-instantiate test-instantiate.c)
|
||||
add_executable(test-import-function test-import-function.c)
|
||||
add_executable(test-memory test-memory.c)
|
||||
add_executable(test-module test-module.c)
|
||||
add_executable(test-validate test-validate.c)
|
||||
add_executable(test-tables test-tables.c)
|
||||
|
||||
find_library(
|
||||
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
|
||||
PATHS ${CMAKE_SOURCE_DIR}/../../../target/debug/
|
||||
)
|
||||
|
||||
if(NOT WASMER_LIB)
|
||||
message(FATAL_ERROR "wasmer library not found")
|
||||
endif()
|
||||
|
||||
target_link_libraries(test-exports
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-globals
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-instantiate
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-import-function
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-memory
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-module
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-validate
|
||||
general ${WASMER_LIB})
|
||||
target_link_libraries(test-tables
|
||||
general ${WASMER_LIB})
|
||||
|
||||
enable_testing()
|
||||
add_test(test-exports test-exports)
|
||||
add_test(test-globals test-globals)
|
||||
add_test(test-instantiate test-instantiate)
|
||||
add_test(test-import-function test-import-function)
|
||||
add_test(test-memory test-memory)
|
||||
add_test(test-module test-module)
|
||||
add_test(test-validate test-validate)
|
||||
add_test(test-tables test-tables)
|
||||
|
39
lib/runtime-c-api/tests/runtime_c_api_tests.rs
Normal file
39
lib/runtime-c-api/tests/runtime_c_api_tests.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
fn test_c_api() {
|
||||
let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests");
|
||||
run_command("cmake", project_tests_dir, Some("."));
|
||||
run_command("make", project_tests_dir, None);
|
||||
run_command("make", project_tests_dir, Some("test"));
|
||||
}
|
||||
|
||||
fn run_command(command_str: &str, dir: &str, arg: Option<&str>) {
|
||||
println!("Running command: `{}` arg: {:?}", command_str, arg);
|
||||
let mut command = Command::new(command_str);
|
||||
if let Some(a) = arg {
|
||||
command.arg(a);
|
||||
}
|
||||
command.current_dir(dir);
|
||||
let result = command.output();
|
||||
match result {
|
||||
Ok(r) => {
|
||||
println!("output:");
|
||||
if let Some(code) = r.status.code() {
|
||||
println!("status: {}", code);
|
||||
} else {
|
||||
println!("status: None");
|
||||
}
|
||||
println!("stdout:");
|
||||
println!("{}", String::from_utf8_lossy(&r.stdout[..]));
|
||||
println!("stderr:");
|
||||
println!("{}", String::from_utf8_lossy(&r.stderr[..]));
|
||||
if r.status.success() {
|
||||
assert!(true)
|
||||
} else {
|
||||
panic!("Command failed with exit status: {:?}", r.status);
|
||||
}
|
||||
}
|
||||
Err(e) => panic!("Command failed: {}", e),
|
||||
}
|
||||
}
|
BIN
lib/runtime-c-api/tests/sum.wasm
Normal file
BIN
lib/runtime-c-api/tests/sum.wasm
Normal file
Binary file not shown.
86
lib/runtime-c-api/tests/test-exports.c
Normal file
86
lib/runtime-c-api/tests/test-exports.c
Normal file
@ -0,0 +1,86 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("sum.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
wasmer_import_t imports[] = {};
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
wasmer_exports_t *exports = NULL;
|
||||
wasmer_instance_exports(instance, &exports);
|
||||
|
||||
int exports_len = wasmer_exports_len(exports);
|
||||
printf("exports_len: %d\n", exports_len);
|
||||
assert(exports_len == 1);
|
||||
|
||||
wasmer_export_t *export = wasmer_exports_get(exports, 0);
|
||||
|
||||
wasmer_import_export_kind kind = wasmer_export_kind(export);
|
||||
assert(kind == WASM_FUNCTION);
|
||||
wasmer_func_t *func = wasmer_export_to_func(export);
|
||||
|
||||
wasmer_byte_array name_bytes = wasmer_export_name(export);
|
||||
assert(name_bytes.bytes_len == 3);
|
||||
char expected[] = {'s', 'u', 'm'};
|
||||
for(int idx = 0; idx < 3; idx++){
|
||||
printf("%c\n", name_bytes.bytes[idx]);
|
||||
assert(name_bytes.bytes[idx] == expected[idx]);
|
||||
}
|
||||
|
||||
uint32_t params_arity;
|
||||
wasmer_func_params_arity(func, ¶ms_arity);
|
||||
assert(params_arity == 2);
|
||||
|
||||
wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity);
|
||||
wasmer_func_params(func, params_sig , params_arity);
|
||||
assert(params_sig[0] == WASM_I32);
|
||||
assert(params_sig[1] == WASM_I32);
|
||||
free(params_sig);
|
||||
|
||||
uint32_t returns_arity;
|
||||
wasmer_func_returns_arity(func, &returns_arity);
|
||||
assert(returns_arity == 1);
|
||||
|
||||
wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity);
|
||||
wasmer_func_returns(func, returns_sig , returns_arity);
|
||||
assert(returns_sig[0] == WASM_I32);
|
||||
free(returns_sig);
|
||||
|
||||
|
||||
// wasmer_value_t param_one;
|
||||
// param_one.tag = WASM_I32;
|
||||
// param_one.value.I32 = 7;
|
||||
// wasmer_value_t param_two;
|
||||
// param_two.tag = WASM_I32;
|
||||
// param_two.value.I32 = 8;
|
||||
// wasmer_value_t params[] = {param_one, param_two};
|
||||
// wasmer_value_t result_one;
|
||||
// wasmer_value_t results[] = {result_one};
|
||||
//
|
||||
// wasmer_result_t call_result = wasmer_func_call(func, params, 2, results, 1);
|
||||
// printf("Call result: %d\n", call_result);
|
||||
// printf("Result: %d\n", results[0].value.I32);
|
||||
// assert(results[0].value.I32 == 15);
|
||||
// assert(call_result == WASMER_OK);
|
||||
|
||||
|
||||
printf("Destroy instance\n");
|
||||
wasmer_instance_destroy(instance);
|
||||
printf("Destroy exports\n");
|
||||
wasmer_exports_destroy(exports);
|
||||
return 0;
|
||||
}
|
30
lib/runtime-c-api/tests/test-globals.c
Normal file
30
lib/runtime-c-api/tests/test-globals.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
wasmer_value_t val;
|
||||
val.tag = WASM_I32;
|
||||
val.value.I32 = 7;
|
||||
wasmer_global_t *global = wasmer_global_new(val, true);
|
||||
|
||||
wasmer_value_t get_val = wasmer_global_get(global);
|
||||
assert( get_val.value.I32 == 7);
|
||||
|
||||
wasmer_value_t val2;
|
||||
val2.tag = WASM_I32;
|
||||
val2.value.I32 = 14;
|
||||
wasmer_global_set(global, val2);
|
||||
|
||||
wasmer_value_t new_get_val = wasmer_global_get(global);
|
||||
assert( new_get_val.value.I32 == 14);
|
||||
|
||||
wasmer_global_descriptor_t desc = wasmer_global_get_descriptor(global);
|
||||
assert(desc.mutable_);
|
||||
assert(desc.kind == WASM_I32);
|
||||
|
||||
wasmer_global_destroy(global);
|
||||
return 0;
|
||||
}
|
91
lib/runtime-c-api/tests/test-import-function.c
Normal file
91
lib/runtime-c-api/tests/test-import-function.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static print_str_called = false;
|
||||
static memory_len = 0;
|
||||
static ptr_len = 0;
|
||||
static char actual_str[14] = {};
|
||||
|
||||
void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len)
|
||||
{
|
||||
wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0);
|
||||
uint32_t mem_len = wasmer_memory_length(memory);
|
||||
uint8_t *mem_bytes = wasmer_memory_data(memory);
|
||||
for (int32_t idx = 0; idx < len; idx++)
|
||||
{
|
||||
actual_str[idx] = mem_bytes[ptr + idx];
|
||||
}
|
||||
actual_str[13] = '\0';
|
||||
printf("In print_str, memory len: %d, ptr_len: %d\n, str %s", mem_len, len, actual_str);
|
||||
print_str_called = true;
|
||||
memory_len = mem_len;
|
||||
ptr_len = len;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32};
|
||||
wasmer_value_tag returns_sig[] = {};
|
||||
|
||||
printf("Creating new func\n");
|
||||
wasmer_func_t *func = wasmer_func_new(print_str, params_sig, 2, returns_sig, 0);
|
||||
wasmer_import_t import;
|
||||
|
||||
char *module_name = "env";
|
||||
wasmer_byte_array module_name_bytes;
|
||||
module_name_bytes.bytes = module_name;
|
||||
module_name_bytes.bytes_len = strlen(module_name);
|
||||
char *import_name = "print_str";
|
||||
wasmer_byte_array import_name_bytes;
|
||||
import_name_bytes.bytes = import_name;
|
||||
import_name_bytes.bytes_len = strlen(import_name);
|
||||
|
||||
import.module_name = module_name_bytes;
|
||||
import.import_name = import_name_bytes;
|
||||
import.tag = WASM_FUNCTION;
|
||||
import.value.func = func;
|
||||
wasmer_import_t imports[] = {import};
|
||||
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("wasm_sample_app.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
printf("Instantiating\n");
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 1);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
wasmer_value_t params[] = {};
|
||||
wasmer_value_t results[] = {};
|
||||
wasmer_result_t call_result = wasmer_instance_call(instance, "hello_wasm", params, 0, results, 0);
|
||||
printf("Call result: %d\n", call_result);
|
||||
|
||||
int error_len = wasmer_last_error_length();
|
||||
printf("Error len: `%d`\n", error_len);
|
||||
char *error_str = malloc(error_len);
|
||||
wasmer_last_error_message(error_str, error_len);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
|
||||
assert(call_result == WASMER_OK);
|
||||
|
||||
assert(print_str_called);
|
||||
assert(memory_len == 17);
|
||||
assert(ptr_len == 13);
|
||||
assert(0 == strcmp(actual_str, "Hello, World!"));
|
||||
|
||||
printf("Destroying func\n");
|
||||
wasmer_func_destroy(func);
|
||||
printf("Destroy instance\n");
|
||||
wasmer_instance_destroy(instance);
|
||||
return 0;
|
||||
}
|
56
lib/runtime-c-api/tests/test-instantiate.c
Normal file
56
lib/runtime-c-api/tests/test-instantiate.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("sum.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
wasmer_import_t imports[] = {};
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
wasmer_value_t param_one;
|
||||
param_one.tag = WASM_I32;
|
||||
param_one.value.I32 = 7;
|
||||
wasmer_value_t param_two;
|
||||
param_two.tag = WASM_I32;
|
||||
param_two.value.I32 = 8;
|
||||
wasmer_value_t params[] = {param_one, param_two};
|
||||
|
||||
wasmer_value_t result_one;
|
||||
wasmer_value_t results[] = {result_one};
|
||||
|
||||
wasmer_result_t call_result = wasmer_instance_call(instance, "sum", params, 2, results, 1);
|
||||
printf("Call result: %d\n", call_result);
|
||||
printf("Result: %d\n", results[0].value.I32);
|
||||
assert(results[0].value.I32 == 15);
|
||||
assert(call_result == WASMER_OK);
|
||||
|
||||
|
||||
wasmer_result_t call_result2 = wasmer_instance_call(instance, "sum", params, 1, results, 1);
|
||||
printf("Call result bad: %d\n", call_result2);
|
||||
assert(call_result2 == WASMER_ERROR);
|
||||
|
||||
int error_len = wasmer_last_error_length();
|
||||
printf("Error len: `%d`\n", error_len);
|
||||
char *error_str = malloc(error_len);
|
||||
wasmer_last_error_message(error_str, error_len);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
assert(0 == strcmp(error_str, "Call error: Parameters of type [I32] did not match signature [I32, I32] -> [I32]"));
|
||||
free(error_str);
|
||||
|
||||
printf("Destroy instance\n");
|
||||
wasmer_instance_destroy(instance);
|
||||
return 0;
|
||||
}
|
62
lib/runtime-c-api/tests/test-memory.c
Normal file
62
lib/runtime-c-api/tests/test-memory.c
Normal file
@ -0,0 +1,62 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
wasmer_memory_t *memory = NULL;
|
||||
wasmer_limits_t descriptor;
|
||||
descriptor.min = 10;
|
||||
wasmer_limit_option_t max;
|
||||
max.has_some = true;
|
||||
max.some = 15;
|
||||
descriptor.max = max;
|
||||
wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor);
|
||||
printf("Memory result: %d\n", memory_result);
|
||||
assert(memory_result == WASMER_OK);
|
||||
|
||||
uint32_t len = wasmer_memory_length(memory);
|
||||
printf("Memory pages length: %d\n", len);
|
||||
assert(len == 10);
|
||||
|
||||
wasmer_result_t grow_result = wasmer_memory_grow(memory, 2);
|
||||
assert(grow_result == WASMER_OK);
|
||||
|
||||
uint32_t new_len = wasmer_memory_length(memory);
|
||||
printf("Memory pages length: %d\n", new_len);
|
||||
assert(new_len == 12);
|
||||
|
||||
uint32_t bytes_len = wasmer_memory_data_length(memory);
|
||||
printf("Memory bytes length: %d\n", bytes_len);
|
||||
assert(bytes_len == 12 * 65536);
|
||||
|
||||
// Err, grow beyond max
|
||||
wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10);
|
||||
assert(grow_result2 == WASMER_ERROR);
|
||||
int error_len = wasmer_last_error_length();
|
||||
char *error_str = malloc(error_len);
|
||||
wasmer_last_error_message(error_str, error_len);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
assert(0 == strcmp(error_str, "unable to grow memory"));
|
||||
free(error_str);
|
||||
|
||||
|
||||
// wasmer_memory_t *bad_memory = NULL;
|
||||
// wasmer_limits_t bad_descriptor;
|
||||
// bad_descriptor.min = 15;
|
||||
// bad_descriptor.max = 10;
|
||||
// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor);
|
||||
// printf("Bad memory result: %d\n", bad_memory_result);
|
||||
// assert(memory_result == WASMER_MEMORY_ERROR);
|
||||
//
|
||||
// int error_len = wasmer_last_error_length();
|
||||
// char *error_str = malloc(error_len);
|
||||
// wasmer_last_error_message(error_str, error_len);
|
||||
// assert(0 == strcmp(error_str, "Creation error"));
|
||||
// free(error_str);
|
||||
|
||||
printf("Destroy memory\n");
|
||||
wasmer_memory_destroy(memory);
|
||||
return 0;
|
||||
}
|
25
lib/runtime-c-api/tests/test-module.c
Normal file
25
lib/runtime-c-api/tests/test-module.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("sum.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
wasmer_module_t *module = NULL;
|
||||
wasmer_result_t compile_result = wasmer_compile(&module, bytes, len);
|
||||
printf("Compile result: %d\n", compile_result);
|
||||
assert(compile_result == WASMER_OK);
|
||||
|
||||
printf("Destroy module\n");
|
||||
wasmer_module_destroy(module);
|
||||
return 0;
|
||||
}
|
48
lib/runtime-c-api/tests/test-tables.c
Normal file
48
lib/runtime-c-api/tests/test-tables.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
wasmer_table_t *table = NULL;
|
||||
wasmer_limits_t descriptor;
|
||||
descriptor.min = 10;
|
||||
wasmer_limit_option_t max;
|
||||
// max.has_some = false;
|
||||
max.has_some = true;
|
||||
max.some = 15;
|
||||
descriptor.max = max;
|
||||
wasmer_result_t table_result = wasmer_table_new(&table, descriptor);
|
||||
printf("Table result: %d\n", table_result);
|
||||
assert(table_result == WASMER_OK);
|
||||
|
||||
uint32_t len = wasmer_table_length(table);
|
||||
printf("Table length: %d\n", len);
|
||||
assert(len == 15);
|
||||
|
||||
// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
|
||||
// assert(grow_result1 == WASMER_OK);
|
||||
// uint32_t len_grow1 = wasmer_table_length(table);
|
||||
// printf("Table length: %d\n", len_grow1);
|
||||
// assert(len_grow1 == 15);
|
||||
|
||||
// // Try to grow beyond max
|
||||
// wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1);
|
||||
// assert(grow_result2 == WASMER_ERROR);
|
||||
// uint32_t len_grow2 = wasmer_table_length(table);
|
||||
// printf("Table length: %d\n", len_grow2);
|
||||
// assert(len_grow2 == 15);
|
||||
|
||||
// wasmer_table_t *table_bad = NULL;
|
||||
// wasmer_limits_t bad_descriptor;
|
||||
// bad_descriptor.min = 15;
|
||||
// bad_descriptor.max = 10;
|
||||
// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor);
|
||||
// printf("Table result: %d\n", table_bad_result);
|
||||
// assert(table_result == WASMER_ERROR);
|
||||
|
||||
printf("Destroy table\n");
|
||||
wasmer_table_destroy(table);
|
||||
return 0;
|
||||
}
|
22
lib/runtime-c-api/tests/test-validate.c
Normal file
22
lib/runtime-c-api/tests/test-validate.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Read the wasm file bytes
|
||||
FILE *file = fopen("sum.wasm", "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long len = ftell(file);
|
||||
uint8_t *bytes = malloc(len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
bool result = wasmer_validate(bytes, len);
|
||||
printf("Result: %d", result);
|
||||
assert(result);
|
||||
|
||||
return 0;
|
||||
}
|
BIN
lib/runtime-c-api/tests/wasm_sample_app.wasm
Executable file
BIN
lib/runtime-c-api/tests/wasm_sample_app.wasm
Executable file
Binary file not shown.
381
lib/runtime-c-api/wasmer.h
Normal file
381
lib/runtime-c-api/wasmer.h
Normal file
@ -0,0 +1,381 @@
|
||||
#ifndef WASMER_H
|
||||
#define WASMER_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum wasmer_import_export_kind {
|
||||
WASM_FUNCTION,
|
||||
WASM_GLOBAL,
|
||||
WASM_MEMORY,
|
||||
WASM_TABLE,
|
||||
};
|
||||
typedef uint32_t wasmer_import_export_kind;
|
||||
|
||||
typedef enum {
|
||||
WASMER_OK = 1,
|
||||
WASMER_ERROR = 2,
|
||||
} wasmer_result_t;
|
||||
|
||||
enum wasmer_value_tag {
|
||||
WASM_I32,
|
||||
WASM_I64,
|
||||
WASM_F32,
|
||||
WASM_F64,
|
||||
};
|
||||
typedef uint32_t wasmer_value_tag;
|
||||
|
||||
typedef struct wasmer_instance_context_t wasmer_instance_context_t;
|
||||
|
||||
typedef struct wasmer_instance_t wasmer_instance_t;
|
||||
|
||||
typedef struct wasmer_module_t wasmer_module_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_export_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *bytes;
|
||||
uint32_t bytes_len;
|
||||
} wasmer_byte_array;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_func_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_exports_t;
|
||||
|
||||
typedef union {
|
||||
int32_t I32;
|
||||
int64_t I64;
|
||||
float F32;
|
||||
double F64;
|
||||
} wasmer_value;
|
||||
|
||||
typedef struct {
|
||||
wasmer_value_tag tag;
|
||||
wasmer_value value;
|
||||
} wasmer_value_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_global_t;
|
||||
|
||||
typedef struct {
|
||||
bool mutable_;
|
||||
wasmer_value_tag kind;
|
||||
} wasmer_global_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_memory_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_table_t;
|
||||
|
||||
typedef union {
|
||||
const wasmer_func_t *func;
|
||||
const wasmer_table_t *table;
|
||||
const wasmer_memory_t *memory;
|
||||
const wasmer_global_t *global;
|
||||
} wasmer_import_export_value;
|
||||
|
||||
typedef struct {
|
||||
wasmer_byte_array module_name;
|
||||
wasmer_byte_array import_name;
|
||||
wasmer_import_export_kind tag;
|
||||
wasmer_import_export_value value;
|
||||
} wasmer_import_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_some;
|
||||
uint32_t some;
|
||||
} wasmer_limit_option_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t min;
|
||||
wasmer_limit_option_t max;
|
||||
} wasmer_limits_t;
|
||||
|
||||
/**
|
||||
* Creates a new Module from the given wasm bytes.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
||||
uint8_t *wasm_bytes,
|
||||
uint32_t wasm_bytes_len);
|
||||
|
||||
/**
|
||||
* Gets wasmer_export kind
|
||||
*/
|
||||
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
|
||||
|
||||
/**
|
||||
* Gets name from wasmer_export
|
||||
*/
|
||||
wasmer_byte_array wasmer_export_name(wasmer_export_t *export_);
|
||||
|
||||
/**
|
||||
* Gets func from wasm_export
|
||||
*/
|
||||
const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_);
|
||||
|
||||
/**
|
||||
* Frees the memory for the given exports
|
||||
*/
|
||||
void wasmer_exports_destroy(wasmer_exports_t *exports);
|
||||
|
||||
/**
|
||||
* Gets wasmer_export by index
|
||||
*/
|
||||
wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx);
|
||||
|
||||
/**
|
||||
* Gets the length of the exports
|
||||
*/
|
||||
int wasmer_exports_len(wasmer_exports_t *exports);
|
||||
|
||||
/**
|
||||
* Calls a `func` with the provided parameters.
|
||||
* Results are set using the provided `results` pointer.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_call(wasmer_func_t *func,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Func
|
||||
*/
|
||||
void wasmer_func_destroy(wasmer_func_t *func);
|
||||
|
||||
/**
|
||||
* Creates new func
|
||||
* The caller owns the object and should call `wasmer_func_destroy` to free it.
|
||||
*/
|
||||
const wasmer_func_t *wasmer_func_new(void (*func)(void *data),
|
||||
const wasmer_value_tag *params,
|
||||
int params_len,
|
||||
const wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the params buffer to the parameter types of the given wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the params of the wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Sets the returns buffer to the parameter types of the given wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_returns(wasmer_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/**
|
||||
* Sets the result parameter to the arity of the returns of the wasmer_func_t
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Global
|
||||
*/
|
||||
void wasmer_global_destroy(wasmer_global_t *global);
|
||||
|
||||
/**
|
||||
* Gets the value stored by the given Global
|
||||
*/
|
||||
wasmer_value_t wasmer_global_get(wasmer_global_t *global);
|
||||
|
||||
/**
|
||||
* Returns a descriptor (type, mutability) of the given Global
|
||||
*/
|
||||
wasmer_global_descriptor_t wasmer_global_get_descriptor(wasmer_global_t *global);
|
||||
|
||||
/**
|
||||
* Creates a new Global and returns a pointer to it.
|
||||
* The caller owns the object and should call `wasmer_global_destroy` to free it.
|
||||
*/
|
||||
wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_);
|
||||
|
||||
/**
|
||||
* Sets the value stored by the given Global
|
||||
*/
|
||||
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
|
||||
|
||||
/**
|
||||
* Calls an instances exported function by `name` with the provided parameters.
|
||||
* Results are set using the provided `results` pointer.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance,
|
||||
const char *name,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/**
|
||||
* Gets the memory within the context at the index `memory_idx`.
|
||||
* The index is always 0 until multiple memories are supported.
|
||||
*/
|
||||
const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx,
|
||||
uint32_t memory_idx);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Instance
|
||||
*/
|
||||
void wasmer_instance_destroy(wasmer_instance_t *instance);
|
||||
|
||||
/**
|
||||
* Gets Exports for the given instance
|
||||
* The caller owns the object and should call `wasmer_exports_destroy` to free it.
|
||||
*/
|
||||
void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports);
|
||||
|
||||
/**
|
||||
* Creates a new Instance from the given wasm bytes and imports.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance,
|
||||
uint8_t *wasm_bytes,
|
||||
uint32_t wasm_bytes_len,
|
||||
wasmer_import_t *imports,
|
||||
int imports_len);
|
||||
|
||||
/**
|
||||
* Gets the length in bytes of the last error.
|
||||
* This can be used to dynamically allocate a buffer with the correct number of
|
||||
* bytes needed to store a message.
|
||||
* # Example
|
||||
* ```
|
||||
* int error_len = wasmer_last_error_length();
|
||||
* char *error_str = malloc(error_len);
|
||||
* ```
|
||||
*/
|
||||
int wasmer_last_error_length(void);
|
||||
|
||||
/**
|
||||
* Stores the last error message into the provided buffer up to the given `length`.
|
||||
* The `length` parameter must be large enough to store the last error message.
|
||||
* Returns the length of the string in bytes.
|
||||
* Returns `-1` if an error occurs.
|
||||
* # Example
|
||||
* ```
|
||||
* int error_len = wasmer_last_error_length();
|
||||
* char *error_str = malloc(error_len);
|
||||
* wasmer_last_error_message(error_str, error_len);
|
||||
* printf("Error str: `%s`\n", error_str);
|
||||
* ```
|
||||
*/
|
||||
int wasmer_last_error_message(char *buffer, int length);
|
||||
|
||||
/**
|
||||
* Gets the start pointer to the bytes within a Memory
|
||||
*/
|
||||
uint8_t *wasmer_memory_data(wasmer_memory_t *mem);
|
||||
|
||||
/**
|
||||
* Gets the size in bytes of a Memory
|
||||
*/
|
||||
uint32_t wasmer_memory_data_length(wasmer_memory_t *mem);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Memory
|
||||
*/
|
||||
void wasmer_memory_destroy(wasmer_memory_t *memory);
|
||||
|
||||
/**
|
||||
* Grows a Memory by the given number of pages.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta);
|
||||
|
||||
/**
|
||||
* Returns the current length in pages of the given memory
|
||||
*/
|
||||
uint32_t wasmer_memory_length(wasmer_memory_t *memory);
|
||||
|
||||
/**
|
||||
* Creates a new Memory for the given descriptor and initializes the given
|
||||
* pointer to pointer to a pointer to the new memory.
|
||||
* The caller owns the object and should call `wasmer_memory_destroy` to free it.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Module
|
||||
*/
|
||||
void wasmer_module_destroy(wasmer_module_t *module);
|
||||
|
||||
/**
|
||||
* Frees memory for the given Table
|
||||
*/
|
||||
void wasmer_table_destroy(wasmer_table_t *table);
|
||||
|
||||
/**
|
||||
* Grows a Table by the given number of elements.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta);
|
||||
|
||||
/**
|
||||
* Returns the current length of the given Table
|
||||
*/
|
||||
uint32_t wasmer_table_length(wasmer_table_t *table);
|
||||
|
||||
/**
|
||||
* Creates a new Table for the given descriptor and initializes the given
|
||||
* pointer to pointer to a pointer to the new Table.
|
||||
* The caller owns the object and should call `wasmer_table_destroy` to free it.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
* and `wasmer_last_error_message` to get an error message.
|
||||
*/
|
||||
wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits);
|
||||
|
||||
/**
|
||||
* Returns true for valid wasm bytes and false for invalid bytes
|
||||
*/
|
||||
bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len);
|
||||
|
||||
#endif /* WASMER_H */
|
306
lib/runtime-c-api/wasmer.hh
Normal file
306
lib/runtime-c-api/wasmer.hh
Normal file
@ -0,0 +1,306 @@
|
||||
#ifndef WASMER_H
|
||||
#define WASMER_H
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
enum class wasmer_import_export_kind : uint32_t {
|
||||
WASM_FUNCTION,
|
||||
WASM_GLOBAL,
|
||||
WASM_MEMORY,
|
||||
WASM_TABLE,
|
||||
};
|
||||
|
||||
enum class wasmer_result_t {
|
||||
WASMER_OK = 1,
|
||||
WASMER_ERROR = 2,
|
||||
};
|
||||
|
||||
enum class wasmer_value_tag : uint32_t {
|
||||
WASM_I32,
|
||||
WASM_I64,
|
||||
WASM_F32,
|
||||
WASM_F64,
|
||||
};
|
||||
|
||||
struct wasmer_instance_context_t;
|
||||
|
||||
struct wasmer_instance_t;
|
||||
|
||||
struct wasmer_module_t;
|
||||
|
||||
struct wasmer_export_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_byte_array {
|
||||
const uint8_t *bytes;
|
||||
uint32_t bytes_len;
|
||||
};
|
||||
|
||||
struct wasmer_func_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_exports_t {
|
||||
|
||||
};
|
||||
|
||||
union wasmer_value {
|
||||
int32_t I32;
|
||||
int64_t I64;
|
||||
float F32;
|
||||
double F64;
|
||||
};
|
||||
|
||||
struct wasmer_value_t {
|
||||
wasmer_value_tag tag;
|
||||
wasmer_value value;
|
||||
};
|
||||
|
||||
struct wasmer_global_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_global_descriptor_t {
|
||||
bool mutable_;
|
||||
wasmer_value_tag kind;
|
||||
};
|
||||
|
||||
struct wasmer_memory_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_table_t {
|
||||
|
||||
};
|
||||
|
||||
union wasmer_import_export_value {
|
||||
const wasmer_func_t *func;
|
||||
const wasmer_table_t *table;
|
||||
const wasmer_memory_t *memory;
|
||||
const wasmer_global_t *global;
|
||||
};
|
||||
|
||||
struct wasmer_import_t {
|
||||
wasmer_byte_array module_name;
|
||||
wasmer_byte_array import_name;
|
||||
wasmer_import_export_kind tag;
|
||||
wasmer_import_export_value value;
|
||||
};
|
||||
|
||||
struct wasmer_limit_option_t {
|
||||
bool has_some;
|
||||
uint32_t some;
|
||||
};
|
||||
|
||||
struct wasmer_limits_t {
|
||||
uint32_t min;
|
||||
wasmer_limit_option_t max;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
/// Creates a new Module from the given wasm bytes.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
||||
uint8_t *wasm_bytes,
|
||||
uint32_t wasm_bytes_len);
|
||||
|
||||
/// Gets wasmer_export kind
|
||||
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
|
||||
|
||||
/// Gets name from wasmer_export
|
||||
wasmer_byte_array wasmer_export_name(wasmer_export_t *export_);
|
||||
|
||||
/// Gets func from wasm_export
|
||||
const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_);
|
||||
|
||||
/// Frees the memory for the given exports
|
||||
void wasmer_exports_destroy(wasmer_exports_t *exports);
|
||||
|
||||
/// Gets wasmer_export by index
|
||||
wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx);
|
||||
|
||||
/// Gets the length of the exports
|
||||
int wasmer_exports_len(wasmer_exports_t *exports);
|
||||
|
||||
/// Calls a `func` with the provided parameters.
|
||||
/// Results are set using the provided `results` pointer.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_call(wasmer_func_t *func,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/// Frees memory for the given Func
|
||||
void wasmer_func_destroy(wasmer_func_t *func);
|
||||
|
||||
/// Creates new func
|
||||
/// The caller owns the object and should call `wasmer_func_destroy` to free it.
|
||||
const wasmer_func_t *wasmer_func_new(void (*func)(void *data),
|
||||
const wasmer_value_tag *params,
|
||||
int params_len,
|
||||
const wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the params buffer to the parameter types of the given wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the params of the wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/// Sets the returns buffer to the parameter types of the given wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_returns(wasmer_func_t *func,
|
||||
wasmer_value_tag *returns,
|
||||
int returns_len);
|
||||
|
||||
/// Sets the result parameter to the arity of the returns of the wasmer_func_t
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result);
|
||||
|
||||
/// Frees memory for the given Global
|
||||
void wasmer_global_destroy(wasmer_global_t *global);
|
||||
|
||||
/// Gets the value stored by the given Global
|
||||
wasmer_value_t wasmer_global_get(wasmer_global_t *global);
|
||||
|
||||
/// Returns a descriptor (type, mutability) of the given Global
|
||||
wasmer_global_descriptor_t wasmer_global_get_descriptor(wasmer_global_t *global);
|
||||
|
||||
/// Creates a new Global and returns a pointer to it.
|
||||
/// The caller owns the object and should call `wasmer_global_destroy` to free it.
|
||||
wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_);
|
||||
|
||||
/// Sets the value stored by the given Global
|
||||
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
|
||||
|
||||
/// Calls an instances exported function by `name` with the provided parameters.
|
||||
/// Results are set using the provided `results` pointer.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance,
|
||||
const char *name,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
|
||||
/// Gets the memory within the context at the index `memory_idx`.
|
||||
/// The index is always 0 until multiple memories are supported.
|
||||
const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t *ctx,
|
||||
uint32_t memory_idx);
|
||||
|
||||
/// Frees memory for the given Instance
|
||||
void wasmer_instance_destroy(wasmer_instance_t *instance);
|
||||
|
||||
/// Gets Exports for the given instance
|
||||
/// The caller owns the object and should call `wasmer_exports_destroy` to free it.
|
||||
void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports);
|
||||
|
||||
/// Creates a new Instance from the given wasm bytes and imports.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance,
|
||||
uint8_t *wasm_bytes,
|
||||
uint32_t wasm_bytes_len,
|
||||
wasmer_import_t *imports,
|
||||
int imports_len);
|
||||
|
||||
/// Gets the length in bytes of the last error.
|
||||
/// This can be used to dynamically allocate a buffer with the correct number of
|
||||
/// bytes needed to store a message.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// int error_len = wasmer_last_error_length();
|
||||
/// char *error_str = malloc(error_len);
|
||||
/// ```
|
||||
int wasmer_last_error_length();
|
||||
|
||||
/// Stores the last error message into the provided buffer up to the given `length`.
|
||||
/// The `length` parameter must be large enough to store the last error message.
|
||||
/// Returns the length of the string in bytes.
|
||||
/// Returns `-1` if an error occurs.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// int error_len = wasmer_last_error_length();
|
||||
/// char *error_str = malloc(error_len);
|
||||
/// wasmer_last_error_message(error_str, error_len);
|
||||
/// printf("Error str: `%s`\n", error_str);
|
||||
/// ```
|
||||
int wasmer_last_error_message(char *buffer, int length);
|
||||
|
||||
/// Gets the start pointer to the bytes within a Memory
|
||||
uint8_t *wasmer_memory_data(wasmer_memory_t *mem);
|
||||
|
||||
/// Gets the size in bytes of a Memory
|
||||
uint32_t wasmer_memory_data_length(wasmer_memory_t *mem);
|
||||
|
||||
/// Frees memory for the given Memory
|
||||
void wasmer_memory_destroy(wasmer_memory_t *memory);
|
||||
|
||||
/// Grows a Memory by the given number of pages.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_memory_grow(wasmer_memory_t *memory, uint32_t delta);
|
||||
|
||||
/// Returns the current length in pages of the given memory
|
||||
uint32_t wasmer_memory_length(wasmer_memory_t *memory);
|
||||
|
||||
/// Creates a new Memory for the given descriptor and initializes the given
|
||||
/// pointer to pointer to a pointer to the new memory.
|
||||
/// The caller owns the object and should call `wasmer_memory_destroy` to free it.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits);
|
||||
|
||||
/// Frees memory for the given Module
|
||||
void wasmer_module_destroy(wasmer_module_t *module);
|
||||
|
||||
/// Frees memory for the given Table
|
||||
void wasmer_table_destroy(wasmer_table_t *table);
|
||||
|
||||
/// Grows a Table by the given number of elements.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_table_grow(wasmer_table_t *table, uint32_t delta);
|
||||
|
||||
/// Returns the current length of the given Table
|
||||
uint32_t wasmer_table_length(wasmer_table_t *table);
|
||||
|
||||
/// Creates a new Table for the given descriptor and initializes the given
|
||||
/// pointer to pointer to a pointer to the new Table.
|
||||
/// The caller owns the object and should call `wasmer_table_destroy` to free it.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
/// and `wasmer_last_error_message` to get an error message.
|
||||
wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits);
|
||||
|
||||
/// Returns true for valid wasm bytes and false for invalid bytes
|
||||
bool wasmer_validate(uint8_t *wasm_bytes, uint32_t wasm_bytes_len);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // WASMER_H
|
@ -260,6 +260,8 @@ impl std::fmt::Display for CallError {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for CallError {}
|
||||
|
||||
/// This error type is produced when creating something,
|
||||
/// like a `Memory` or a `Table`.
|
||||
#[derive(Debug, Clone)]
|
||||
|
199
lib/spectests/spectests/README.md
vendored
199
lib/spectests/spectests/README.md
vendored
@ -1,136 +1,135 @@
|
||||
This directory contains tests for the core WebAssembly semantics, as described in [Semantics.md](https://github.com/WebAssembly/design/blob/master/Semantics.md) and specified by the [spec interpreter](https://github.com/WebAssembly/spec/blob/master/interpreter/spec).
|
||||
|
||||
This files should be a direct copy of the original [WebAssembly spec tests](https://github.com/WebAssembly/spec/tree/master/test/core).
|
||||
These files should be a direct copy of the original [WebAssembly spec tests](/test/core).
|
||||
|
||||
Tests are written in the [S-Expression script format](https://github.com/WebAssembly/spec/blob/master/interpreter/README.md#s-expression-syntax) defined by the interpreter.
|
||||
|
||||
## Autogenerated Rust test cases
|
||||
|
||||
This files will serve as base for autogenerating Rust testcases
|
||||
These files will serve as a base for autogenerating Rust testcases
|
||||
when `WASM_GENERATE_SPECTESTS=1 cargo build` is executed
|
||||
([src/build_spectests.rs](https://github.com/wasmerio/wasmer/blob/master/src/build_spectests.rs)).
|
||||
([src/build_spectests.rs](/src/build_spectests.rs)).
|
||||
|
||||
The result autogenerated spectests live in the [src/spectests](https://github.com/wasmerio/wasmer/tree/master/src/spectests)
|
||||
directory.
|
||||
The resulting autogenerated spec tests live in the [src/spectests](/src/spectests).
|
||||
|
||||
## Testcases
|
||||
|
||||
Currently supported command assertions:
|
||||
|
||||
- [x] Module _mostly implemented_ (it should support named modules `(module $Xx)`).
|
||||
- [x] AssertReturn _mostly implemented_ (it should support calls to named modules `(invoke $Xx "call")`).
|
||||
- [x] AssertReturnCanonicalNan _fully implemented_
|
||||
- [x] AssertReturnArithmeticNan _fully implemented_
|
||||
- [x] AssertTrap _fully implemented_
|
||||
- [x] AssertInvalid _Fully implemented_ (it should not require to do validation separate from compilation)
|
||||
- [x] AssertMalformed _Fully implemented_
|
||||
- [ ] AssertUninstantiable _not implemented yet_
|
||||
- [ ] AssertExhaustion _not implemented yet_
|
||||
- [ ] Register _not implemented yet_
|
||||
- [x] PerformAction _partially implemented, only function invokations for now_
|
||||
- [x] `module` _mostly implemented_ (it should support named modules `(module $Xx)`).
|
||||
- [x] `assert_return` _mostly implemented_ (it should support calls to named modules `(invoke $Xx "call")`).
|
||||
- [x] `assert_return_canonical_nan` _fully implemented_
|
||||
- [x] `assert_return_arithmetic_nan` _fully implemented_
|
||||
- [x] `assert_trap` _fully implemented_
|
||||
- [x] `assert_invalid` _fully implemented_ (it should not require validation to be performed separate from compilation)
|
||||
- [x] `assert_malformed` _fully implemented_
|
||||
- [ ] `assert_uninstantiable` _not implemented yet_
|
||||
- [ ] `assert_exhaustion` _not implemented yet_
|
||||
- [ ] `register` _not implemented yet_
|
||||
- [x] `perform_action` _partially implemented, only function invocations for now_
|
||||
|
||||
### Covered spectests
|
||||
### Covered spec tests
|
||||
|
||||
This spectests are currently covered:
|
||||
The following spec tests are currently covered:
|
||||
|
||||
- address.wast ✅
|
||||
- align.wast ✅
|
||||
- binary.wast ✅
|
||||
- block.wast ✅
|
||||
- br.wast ✅
|
||||
- br_if.wast ✅
|
||||
- br_table.wast ✅
|
||||
- break-drop.wast ✅
|
||||
- call.wast ✅
|
||||
- call_indirect.wast ✅
|
||||
- comments.wast ✅
|
||||
- const.wast ✅
|
||||
- conversions.wast ✅
|
||||
- custom.wast ✅
|
||||
- data.wast ✅
|
||||
- elem.wast
|
||||
- endianness.wast ✅
|
||||
- exports.wast ✅
|
||||
- f32.wast ✅
|
||||
- f32_bitwise.wast ✅
|
||||
- f32_cmp.wast ✅
|
||||
- f64.wast ✅
|
||||
- f64_bitwise.wast ✅
|
||||
- f64_cmp.wast ✅
|
||||
- fac.wast ✅
|
||||
- float_exprs.wast ✅
|
||||
- float_literals.wast ✅
|
||||
- float_memory.wast ✅
|
||||
- float_misc.wast ✅
|
||||
- forward.wast ✅
|
||||
- func.wast ✅
|
||||
- func_ptrs.wast ✅
|
||||
- get_local.wast ✅
|
||||
- globals.wast ✅
|
||||
- i32.wast ✅
|
||||
- i64.wast ✅
|
||||
- if.wast ✅
|
||||
- imports.wast
|
||||
- inline-module.wast
|
||||
- int_exprs.wast ✅
|
||||
- int_literals.wast ✅
|
||||
- labels.wast ✅
|
||||
- left-to-right.wast ✅
|
||||
- linking.wast
|
||||
- loop.wast ✅
|
||||
- memory.wast ✅
|
||||
- memory_grow.wast ✅
|
||||
- memory_redundancy.wast ✅
|
||||
- memory_trap.wast ✅
|
||||
- names.wast ✅
|
||||
- nop.wast ✅
|
||||
- return.wast ✅
|
||||
- select.wast ✅
|
||||
- set_local.wast ✅
|
||||
- skip-stack-guard-page.wast
|
||||
- stack.wast ✅
|
||||
- start.wast ✅
|
||||
- store_retval.wast ✅
|
||||
- switch.wast ✅
|
||||
- tee_local.wast ✅
|
||||
- token.wast ✅
|
||||
- traps.wast ✅
|
||||
- type.wast ✅
|
||||
- typecheck.wast ✅
|
||||
- unreachable.wast
|
||||
- unreached-invalid.wast
|
||||
- unwind.wast ✅
|
||||
- utf8-custom-section-id.wast
|
||||
- utf8-import-field.wast
|
||||
- utf8-import-module.wast
|
||||
- utf8-invalid-encoding.wast
|
||||
- [x] address.wast
|
||||
- [x] align.wast
|
||||
- [x] binary.wast
|
||||
- [x] block.wast
|
||||
- [x] br.wast
|
||||
- [x] br_if.wast
|
||||
- [x] br_table.wast
|
||||
- [x] break-drop.wast
|
||||
- [x] call.wast
|
||||
- [x] call_indirect.wast
|
||||
- [x] comments.wast
|
||||
- [x] const.wast
|
||||
- [x] conversions.wast
|
||||
- [x] custom.wast
|
||||
- [x] data.wast
|
||||
- [ ] elem.wast
|
||||
- [x] endianness.wast
|
||||
- [x] exports.wast
|
||||
- [x] f32.wast
|
||||
- [x] f32_bitwise.wast
|
||||
- [x] f32_cmp.wast
|
||||
- [x] f64.wast
|
||||
- [x] f64_bitwise.wast
|
||||
- [x] f64_cmp.wast
|
||||
- [x] fac.wast
|
||||
- [x] float_exprs.wast
|
||||
- [x] float_literals.wast
|
||||
- [x] float_memory.wast
|
||||
- [x] float_misc.wast
|
||||
- [x] forward.wast
|
||||
- [x] func.wast
|
||||
- [x] func_ptrs.wast
|
||||
- [x] get_local.wast
|
||||
- [x] globals.wast
|
||||
- [x] i32.wast
|
||||
- [x] i64.wast
|
||||
- [x] if.wast
|
||||
- [ ] imports.wast
|
||||
- [ ] inline-module.wast
|
||||
- [x] int_exprs.wast
|
||||
- [x] int_literals.wast
|
||||
- [x] labels.wast
|
||||
- [x] left-to-right.wast
|
||||
- [ ] linking.wast
|
||||
- [x] loop.wast
|
||||
- [x] memory.wast
|
||||
- [x] memory_grow.wast
|
||||
- [x] memory_redundancy.wast
|
||||
- [x] memory_trap.wast
|
||||
- [x] names.wast
|
||||
- [x] nop.wast
|
||||
- [x] return.wast
|
||||
- [x] select.wast
|
||||
- [x] set_local.wast
|
||||
- [ ] skip-stack-guard-page.wast
|
||||
- [x] stack.wast
|
||||
- [x] start.wast
|
||||
- [x] store_retval.wast
|
||||
- [x] switch.wast
|
||||
- [x] tee_local.wast
|
||||
- [x] token.wast
|
||||
- [x] traps.wast
|
||||
- [x] type.wast
|
||||
- [x] typecheck.wast
|
||||
- [ ] unreachable.wast
|
||||
- [ ] unreached-invalid.wast
|
||||
- [x] unwind.wast
|
||||
- [ ] utf8-custom-section-id.wast
|
||||
- [ ] utf8-import-field.wast
|
||||
- [ ] utf8-import-module.wast
|
||||
- [ ] utf8-invalid-encoding.wast
|
||||
|
||||
### Specific non-supported cases
|
||||
|
||||
There are some cases that we decided to skip for now to fasten the time to release:
|
||||
There are some cases that we decided to skip for now to accelerate the release schedule:
|
||||
|
||||
- `SKIP_MUTABLE_GLOBALS`: Right now the WASM parser can't validate a module with imported/exported mut globals. We decided to skip the tests until Cranelift and wasmparser can handle this (original spec proposal: https://github.com/WebAssembly/mutable-global). Spectests affected:
|
||||
- `SKIP_MUTABLE_GLOBALS`: Right now the Wasm parser can't validate a module with imported/exported `mut` globals. We decided to skip the tests until Cranelift and wasmparser can handle this (see [original spec proposal](https://github.com/WebAssembly/mutable-global)). Spec tests affected:
|
||||
- `globals.wast`
|
||||
- `SKIP_CALL_INDIRECT_TYPE_MISMATCH`: we implemented traps in a fast way. We haven't covered yet the type mismatch on `call_indirect`. Specs affected:
|
||||
- `SKIP_CALL_INDIRECT_TYPE_MISMATCH`: we implemented traps in a fast way. We haven't yet covered the type mismatch on `call_indirect`. Specs affected:
|
||||
|
||||
- `call_indirect.wast`
|
||||
|
||||
- `SKIP_CALL_UNDEFINED_ELEMENT`
|
||||
Tables are imported into every spec module, even for modules that don't expect it. We need to figure out a way to prevent import of objects that are not explicitly imported into the module.
|
||||
Tables are imported into every spec module, even for modules that don't expect it. We need to figure out a way to prevent importing of objects that are not explicitly imported into the module.
|
||||
|
||||
Currently cranelift_wasm::ModuleEnvironment does not provide `declare_table_import`, etc. so there is no meaningful way of fixing this yet.
|
||||
Currently `cranelift_wasm::ModuleEnvironment` does not provide `declare_table_import`, etc. so there is no meaningful way of fixing this yet.
|
||||
|
||||
- `call_indirect.wast`
|
||||
|
||||
- `SKIP_SHARED_TABLE` [elem.wast]
|
||||
Currently sharing tables between instances/modules does not work. Below are some of the reasons it is hard to achieve.
|
||||
Currently sharing tables between instances/modules does not work. Below are some of the reasons it is hard to achieve:
|
||||
|
||||
- Rust naturally prevents such because of the possibility of race conditions
|
||||
- ImportObject is just a wrapper, what we really care about is references to its content.
|
||||
- Instance::new contains a mutation points, the part where after getting the object (memory or table) we push values to it
|
||||
table[table_element_index] = func_addr
|
||||
- Instance has its own created memories and tables and references to them must outlive Instance::new()
|
||||
- Possible strategy
|
||||
- `ImportObject` is just a wrapper, what we really care about is references to its content.
|
||||
- `Instance::new` contains a mutation points, the part where after getting the object (memory or table) we push values to it
|
||||
`table[table_element_index] = func_addr`
|
||||
- Instance has its own created memories and tables and references to them must outlive `Instance::new()`
|
||||
- Possible strategy:
|
||||
|
||||
```rust
|
||||
// ImportObject should be passed by ref
|
||||
|
Loading…
Reference in New Issue
Block a user