mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-08 05:38:19 +00:00
Merge branch 'master' into js-api-improvement
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
[target.'cfg(target_os = "linux")']
|
||||
[target.'cfg(all(target_os = "linux", target_env = "gnu"))']
|
||||
rustflags = [
|
||||
# Put the VM functions in the dynamic symbol table.
|
||||
"-C", "link-arg=-Wl,-E",
|
||||
|
||||
10
.github/workflows/documentation.yaml
vendored
10
.github/workflows/documentation.yaml
vendored
@@ -22,14 +22,14 @@ jobs:
|
||||
- name: Install LLVM
|
||||
shell: bash
|
||||
run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf ${{ env.LLVM_URL }} -L -o llvm.tar.gz
|
||||
curl --proto '=https' --tlsv1.2 -sSf ${{ env.LLVM_URL }} -L -o llvm.tar.xz
|
||||
mkdir ${{ env.LLVM_DIR }}
|
||||
tar xf llvm.tar.gz --strip-components=1 -C ${{ env.LLVM_DIR }}
|
||||
tar xf llvm.tar.xz --strip-components=1 -C ${{ env.LLVM_DIR }}
|
||||
echo "${{ env.LLVM_DIR }}/bin" >> $GITHUB_PATH
|
||||
echo "LLVM_SYS_110_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV
|
||||
echo "LLVM_SYS_120_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV
|
||||
env:
|
||||
LLVM_DIR: ${{ github.workspace }}/llvm-11
|
||||
LLVM_URL: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz'
|
||||
LLVM_DIR: ${{ github.workspace }}/llvm-13
|
||||
LLVM_URL: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz'
|
||||
- name: Build & package documentation
|
||||
run: make package-docs
|
||||
- name: Publish documentation
|
||||
|
||||
10
.github/workflows/lint.yaml
vendored
10
.github/workflows/lint.yaml
vendored
@@ -23,11 +23,11 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
- name: Install LLVM (Linux)
|
||||
run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz -L -o /opt/llvm.tar.gz
|
||||
mkdir -p /opt/llvm-11
|
||||
tar xf /opt/llvm.tar.gz --strip-components=1 -C /opt/llvm-11
|
||||
echo '/opt/llvm-11/bin' >> $GITHUB_PATH
|
||||
echo 'LLVM_SYS_110_PREFIX=/opt/llvm-11' >> $GITHUB_ENV
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz -L -o /opt/llvm.tar.xz
|
||||
mkdir -p /opt/llvm-12
|
||||
tar xf /opt/llvm.tar.xz --strip-components=1 -C /opt/llvm-12
|
||||
echo '/opt/llvm-12/bin' >> $GITHUB_PATH
|
||||
echo 'LLVM_SYS_120_PREFIX=/opt/llvm-12' >> $GITHUB_ENV
|
||||
- run: make lint
|
||||
env:
|
||||
ENABLE_CRANELIFT: "1"
|
||||
|
||||
18
.github/workflows/test-sys.yaml
vendored
18
.github/workflows/test-sys.yaml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
include:
|
||||
- build: linux-x64
|
||||
os: ubuntu-18.04
|
||||
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz'
|
||||
llvm_url: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz'
|
||||
artifact_name: 'wasmer-linux-amd64'
|
||||
cross_compilation_artifact_name: 'cross_compiled_from_linux'
|
||||
run_test: true
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
use_sccache: true
|
||||
- build: macos-x64
|
||||
os: macos-11
|
||||
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/darwin-amd64.tar.gz'
|
||||
llvm_url: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-apple-darwin.tar.xz'
|
||||
artifact_name: 'wasmer-darwin-amd64'
|
||||
cross_compilation_artifact_name: 'cross_compiled_from_mac'
|
||||
run_test: true
|
||||
@@ -68,8 +68,8 @@ jobs:
|
||||
run_test_capi: false
|
||||
- build: windows-x64
|
||||
os: windows-latest
|
||||
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/windows-amd64.tar.gz'
|
||||
llvm_choco_version: 12.0.1
|
||||
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/12.x/windows-amd64.tar.gz'
|
||||
llvm_choco_version: 13.0.0
|
||||
artifact_name: 'wasmer-windows-amd64'
|
||||
cross_compilation_artifact_name: 'cross_compiled_from_win'
|
||||
run_integration_tests: true
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
# os: [self-hosted, linux, ARM64]
|
||||
# random_sccache_port: true
|
||||
# use_sccache: true
|
||||
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-aarch64.tar.gz'
|
||||
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/12.x/linux-aarch64.tar.gz'
|
||||
# artifact_name: 'wasmer-linux-aarch64'
|
||||
# run_integration_tests: false
|
||||
- build: linux-musl-x64
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
choco install llvm --version ${{ matrix.llvm_choco_version }} --allow-downgrade
|
||||
cd 'C:\Program Files\LLVM\'
|
||||
LLVM_DIR=$(pwd)
|
||||
echo "LLVM_SYS_110_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
|
||||
echo "LLVM_SYS_120_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
|
||||
- name: Install LLVM (macOS Apple Silicon)
|
||||
if: matrix.os == 'macos-11.0' && !matrix.llvm_url
|
||||
run: |
|
||||
@@ -131,12 +131,12 @@ jobs:
|
||||
if: matrix.llvm_url
|
||||
shell: bash
|
||||
run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf ${{ matrix.llvm_url }} -L -o llvm.tar.gz
|
||||
curl --proto '=https' --tlsv1.2 -sSf ${{ matrix.llvm_url }} -L -o llvm.tar.xz
|
||||
LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }}
|
||||
mkdir ${LLVM_DIR}
|
||||
tar xf llvm.tar.gz --strip-components=1 -C ${LLVM_DIR}
|
||||
tar xf llvm.tar.xz --strip-components=1 -C ${LLVM_DIR}
|
||||
echo "${LLVM_DIR}/bin" >> $GITHUB_PATH
|
||||
echo "LLVM_SYS_110_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
|
||||
echo "LLVM_SYS_120_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
|
||||
env:
|
||||
LLVM_DIR: .llvm
|
||||
- name: Set up dependencies for Mac OS
|
||||
|
||||
54
Cargo.lock
generated
54
Cargo.lock
generated
@@ -210,6 +210,27 @@ version = "3.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb738a1e65989ecdcd5bba16079641bd7209688fa546e1064832fd6e012fd32a"
|
||||
dependencies = [
|
||||
"bytecheck_derive",
|
||||
"ptr_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck_derive"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3b4dff26fdc9f847dab475c9fec16f2cba82d5aa1f09981b87c44520721e10a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
@@ -1156,9 +1177,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "llvm-sys"
|
||||
version = "110.0.2"
|
||||
version = "120.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b7cc88ba864d592f52132ed3a19a97118fe16c92a63961f54b0ab7279c5407f"
|
||||
checksum = "b4a810627ac62b396f5fd2214ba9bbd8748d4d6efdc4d2c1c1303ea7a75763ce"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"lazy_static",
|
||||
@@ -1773,22 +1794,33 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.6.7"
|
||||
name = "rend"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb135b3e5e3311f0a254bfb00333f4bac9ef1d89888b84242a89eb8722b09a07"
|
||||
checksum = "6d0351a2e529ee30d571ef31faa5a4e0b9addaad087697b77efb20d2809e41c7"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"bytecheck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e419b2e30d088b21c4bf3072561535305df8066e89937ad05fc205b99874c23c"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
"hashbrown 0.11.2",
|
||||
"ptr_meta",
|
||||
"rend",
|
||||
"rkyv_derive",
|
||||
"seahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.6.7"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba8f489f6b6d8551bb15904293c1ad58a6abafa7d8390d15f7ed05a2afcd87d5"
|
||||
checksum = "2ae58c4ba80f15f2f0842f4c61729e92c4e33a09bd78196c2b1ab9b0771a3ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2723,7 +2755,6 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"paste",
|
||||
"rayon",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"typetag",
|
||||
@@ -2901,6 +2932,7 @@ name = "wasmer-engine"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"enumset",
|
||||
"lazy_static",
|
||||
"loupe",
|
||||
"memmap2",
|
||||
@@ -2920,6 +2952,7 @@ name = "wasmer-engine-dummy"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"enumset",
|
||||
"loupe",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
@@ -2934,6 +2967,7 @@ name = "wasmer-engine-dylib"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"enumset",
|
||||
"leb128",
|
||||
"libloading",
|
||||
"loupe",
|
||||
@@ -2955,6 +2989,7 @@ version = "2.0.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"cfg-if 1.0.0",
|
||||
"enumset",
|
||||
"leb128",
|
||||
"libloading",
|
||||
"loupe",
|
||||
@@ -2973,6 +3008,7 @@ name = "wasmer-engine-universal"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"enumset",
|
||||
"leb128",
|
||||
"loupe",
|
||||
"region",
|
||||
|
||||
17
Makefile
17
Makefile
@@ -134,24 +134,19 @@ ifneq ($(ENABLE_LLVM), 0)
|
||||
LLVM_VERSION := $(shell llvm-config --version)
|
||||
|
||||
# If findstring is not empty, then it have found the value
|
||||
ifneq (, $(findstring 12,$(LLVM_VERSION)))
|
||||
ifneq (, $(findstring 13,$(LLVM_VERSION)))
|
||||
compilers += llvm
|
||||
else ifneq (, $(findstring 11,$(LLVM_VERSION)))
|
||||
compilers += llvm
|
||||
else ifneq (, $(findstring 10,$(LLVM_VERSION)))
|
||||
else ifneq (, $(findstring 12,$(LLVM_VERSION)))
|
||||
compilers += llvm
|
||||
endif
|
||||
# … or try to autodetect LLVM from `llvm-config-<version>`.
|
||||
else
|
||||
ifneq (, $(shell which llvm-config-12 2>/dev/null))
|
||||
ifneq (, $(shell which llvm-config-13 2>/dev/null))
|
||||
LLVM_VERSION := $(shell llvm-config-13 --version)
|
||||
compilers += llvm
|
||||
else ifneq (, $(shell which llvm-config-12 2>/dev/null))
|
||||
LLVM_VERSION := $(shell llvm-config-12 --version)
|
||||
compilers += llvm
|
||||
else ifneq (, $(shell which llvm-config-11 2>/dev/null))
|
||||
LLVM_VERSION := $(shell llvm-config-11 --version)
|
||||
compilers += llvm
|
||||
else ifneq (, $(shell which llvm-config-10 2>/dev/null))
|
||||
LLVM_VERSION := $(shell llvm-config-10 --version)
|
||||
compilers += llvm
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -57,3 +57,8 @@ required-features = ["universal", "cranelift"]
|
||||
name = "dylib_cranelift"
|
||||
path = "fuzz_targets/dylib_cranelift.rs"
|
||||
required-features = ["dylib", "cranelift"]
|
||||
|
||||
[[bin]]
|
||||
name = "deterministic"
|
||||
path = "fuzz_targets/deterministic.rs"
|
||||
required-features = ["universal", "dylib", "cranelift", "llvm", "singlepass"]
|
||||
81
fuzz/fuzz_targets/deterministic.rs
Normal file
81
fuzz/fuzz_targets/deterministic.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target};
|
||||
use wasm_smith::{Config, ConfiguredModule};
|
||||
use wasmer::{CompilerConfig, Engine, Module, Store};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
use wasmer_compiler_llvm::LLVM;
|
||||
use wasmer_compiler_singlepass::Singlepass;
|
||||
use wasmer_engine_dylib::Dylib;
|
||||
use wasmer_engine_universal::Universal;
|
||||
|
||||
#[derive(Arbitrary, Debug, Default, Copy, Clone)]
|
||||
struct NoImportsConfig;
|
||||
impl Config for NoImportsConfig {
|
||||
fn max_imports(&self) -> usize {
|
||||
0
|
||||
}
|
||||
fn max_memory_pages(&self) -> u32 {
|
||||
// https://github.com/wasmerio/wasmer/issues/2187
|
||||
65535
|
||||
}
|
||||
fn allow_start_export(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_and_compare(name: &str, engine: impl Engine, wasm: &[u8]) {
|
||||
let store = Store::new(&engine);
|
||||
|
||||
// compile for first time
|
||||
let module = Module::new(&store, wasm).unwrap();
|
||||
let first = module.serialize().unwrap();
|
||||
|
||||
// compile for second time
|
||||
let module = Module::new(&store, wasm).unwrap();
|
||||
let second = module.serialize().unwrap();
|
||||
|
||||
if first != second {
|
||||
panic!("non-deterministic compilation from {}", name);
|
||||
}
|
||||
}
|
||||
|
||||
fuzz_target!(|module: ConfiguredModule<NoImportsConfig>| {
|
||||
let wasm_bytes = module.to_bytes();
|
||||
|
||||
let mut compiler = Cranelift::default();
|
||||
compiler.canonicalize_nans(true);
|
||||
compiler.enable_verifier();
|
||||
compile_and_compare(
|
||||
"universal-cranelift",
|
||||
Universal::new(compiler.clone()).engine(),
|
||||
&wasm_bytes,
|
||||
);
|
||||
//compile_and_compare(
|
||||
// "dylib-cranelift",
|
||||
// Dylib::new(compiler).engine(),
|
||||
// &wasm_bytes,
|
||||
//);
|
||||
|
||||
let mut compiler = LLVM::default();
|
||||
compiler.canonicalize_nans(true);
|
||||
compiler.enable_verifier();
|
||||
compile_and_compare(
|
||||
"universal-llvm",
|
||||
Universal::new(compiler.clone()).engine(),
|
||||
&wasm_bytes,
|
||||
);
|
||||
//compile_and_compare("dylib-llvm", Dylib::new(compiler).engine(), &wasm_bytes);
|
||||
|
||||
let compiler = Singlepass::default();
|
||||
compile_and_compare(
|
||||
"universal-singlepass",
|
||||
Universal::new(compiler.clone()).engine(),
|
||||
&wasm_bytes,
|
||||
);
|
||||
//compile_and_compare(
|
||||
// "dylib-singlepass",
|
||||
// Dylib::new(compiler).engine(),
|
||||
// &wasm_bytes,
|
||||
//);
|
||||
});
|
||||
2
lib/api/src/js/externals/function.rs
vendored
2
lib/api/src/js/externals/function.rs
vendored
@@ -1288,7 +1288,7 @@ mod inner {
|
||||
|
||||
#[test]
|
||||
fn test_into_array() {
|
||||
assert_eq!(().into_array(), []);
|
||||
assert_eq!(().into_array(), [0i128; 0]);
|
||||
assert_eq!((1).into_array(), [1]);
|
||||
assert_eq!((1i32, 2i64).into_array(), [1, 2]);
|
||||
assert_eq!(
|
||||
|
||||
2
lib/api/src/sys/externals/function.rs
vendored
2
lib/api/src/sys/externals/function.rs
vendored
@@ -1472,7 +1472,7 @@ mod inner {
|
||||
|
||||
#[test]
|
||||
fn test_into_array() {
|
||||
assert_eq!(().into_array(), []);
|
||||
assert_eq!(().into_array(), [0i128; 0]);
|
||||
assert_eq!((1).into_array(), [1]);
|
||||
assert_eq!((1i32, 2i64).into_array(), [1, 2]);
|
||||
assert_eq!(
|
||||
|
||||
@@ -58,6 +58,11 @@ pub enum InstantiationError {
|
||||
#[error(transparent)]
|
||||
Start(RuntimeError),
|
||||
|
||||
/// The module was compiled with a CPU feature that is not available on
|
||||
/// the current host.
|
||||
#[error("missing requires CPU features: {0:?}")]
|
||||
CpuFeature(String),
|
||||
|
||||
/// Error occurred when initializing the host environment.
|
||||
#[error(transparent)]
|
||||
HostEnvInitialization(HostEnvInitError),
|
||||
@@ -68,6 +73,7 @@ impl From<wasmer_engine::InstantiationError> for InstantiationError {
|
||||
match other {
|
||||
wasmer_engine::InstantiationError::Link(e) => Self::Link(e),
|
||||
wasmer_engine::InstantiationError::Start(e) => Self::Start(e),
|
||||
wasmer_engine::InstantiationError::CpuFeature(e) => Self::CpuFeature(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ serde = { version = "1", optional = true, features = ["derive"] }
|
||||
thiserror = "1"
|
||||
typetag = { version = "0.1", optional = true }
|
||||
paste = "1.0"
|
||||
rayon = "1.5"
|
||||
|
||||
[dev-dependencies]
|
||||
field-offset = "0.3.3"
|
||||
|
||||
@@ -103,12 +103,15 @@ int main(int argc, const char* argv[]) {
|
||||
wasmer_last_error_message(error_message, error_length);
|
||||
|
||||
printf("Attempted to set an immutable global: `%s`\n", error_message);
|
||||
free(error_message);
|
||||
}
|
||||
|
||||
wasm_val_t some_set_value = WASM_F32_VAL(21);
|
||||
wasm_global_set(some, &some_set_value);
|
||||
printf("`some` value: %.1f\n", some_value.of.f32);
|
||||
|
||||
wasm_globaltype_delete(one_type);
|
||||
wasm_globaltype_delete(some_type);
|
||||
wasm_module_delete(module);
|
||||
wasm_extern_vec_delete(&exports);
|
||||
wasm_instance_delete(instance);
|
||||
|
||||
@@ -63,6 +63,8 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
printf("Instantiating module...\n");
|
||||
wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL);
|
||||
wasm_func_delete(host_func);
|
||||
wasm_global_delete(host_global);
|
||||
|
||||
if (!instance) {
|
||||
printf("> Error instantiating module!\n");
|
||||
|
||||
@@ -15,6 +15,7 @@ int main(int argc, const char* argv[]) {
|
||||
wasm_byte_vec_new(&wat, strlen(wat_string), wat_string);
|
||||
wasm_byte_vec_t wasm_bytes;
|
||||
wat2wasm(&wat, &wasm_bytes);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
printf("Creating the store...\n");
|
||||
wasm_engine_t* engine = wasm_engine_new();
|
||||
|
||||
@@ -69,13 +69,7 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
// Instantiate.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_importtype_vec_t import_types;
|
||||
wasm_module_imports(module, &import_types);
|
||||
|
||||
wasm_extern_vec_t imports;
|
||||
wasm_extern_vec_new_uninitialized(&imports, import_types.size);
|
||||
wasm_importtype_vec_delete(&import_types);
|
||||
|
||||
bool get_imports_result = wasi_get_imports(store, module, wasi_env, &imports);
|
||||
|
||||
if (!get_imports_result) {
|
||||
@@ -153,6 +147,7 @@ int main(int argc, const char* argv[]) {
|
||||
fclose(memory_stream);
|
||||
|
||||
printf("WASI Stdout: `%.*s`\n", (int) stdout_size, stdout);
|
||||
free(stdout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -49,13 +49,12 @@
|
||||
|
||||
use libc::{c_char, c_int};
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fmt::Display;
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::slice;
|
||||
|
||||
thread_local! {
|
||||
static LAST_ERROR: RefCell<Option<Box<dyn Error>>> = RefCell::new(None);
|
||||
static LAST_ERROR: RefCell<Option<String>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
/// Rust function to register a new error.
|
||||
@@ -63,24 +62,23 @@ thread_local! {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use wasmer::error::{update_last_error, CApiError};
|
||||
/// # use wasmer::error::update_last_error;
|
||||
///
|
||||
/// update_last_error(CApiError {
|
||||
/// msg: "Hello, World!".to_string(),
|
||||
/// });
|
||||
/// update_last_error("Hello, World!");
|
||||
/// ```
|
||||
pub fn update_last_error<E: Error + 'static>(err: E) {
|
||||
pub fn update_last_error<E: Display>(err: E) {
|
||||
LAST_ERROR.with(|prev| {
|
||||
*prev.borrow_mut() = Some(Box::new(err));
|
||||
*prev.borrow_mut() = Some(err.to_string());
|
||||
});
|
||||
}
|
||||
|
||||
/// Retrieve the most recent error, clearing it in the process.
|
||||
pub(crate) fn take_last_error() -> Option<Box<dyn Error>> {
|
||||
pub(crate) fn take_last_error() -> Option<String> {
|
||||
LAST_ERROR.with(|prev| prev.borrow_mut().take())
|
||||
}
|
||||
|
||||
/// Gets the length in bytes of the last error if any, zero otherwise.
|
||||
/// Gets the length in bytes of the last error if any, zero otherwise. This
|
||||
/// includes th NUL terminator byte.
|
||||
///
|
||||
/// This can be used to dynamically allocate a buffer with the correct number of
|
||||
/// bytes needed to store a message.
|
||||
@@ -88,10 +86,11 @@ pub(crate) fn take_last_error() -> Option<Box<dyn Error>> {
|
||||
/// # Example
|
||||
///
|
||||
/// See this module's documentation to get a complete example.
|
||||
// TODO(Amanieu): This should use size_t
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasmer_last_error_length() -> c_int {
|
||||
LAST_ERROR.with(|prev| match *prev.borrow() {
|
||||
Some(ref err) => err.to_string().len() as c_int + 1,
|
||||
Some(ref err) => err.len() as c_int + 1,
|
||||
None => 0,
|
||||
})
|
||||
}
|
||||
@@ -118,6 +117,7 @@ pub extern "C" fn wasmer_last_error_length() -> c_int {
|
||||
/// # Example
|
||||
///
|
||||
/// See this module's documentation to get a complete example.
|
||||
// TODO(Amanieu): This should use size_t
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_last_error_message(
|
||||
buffer: Option<NonNull<c_char>>,
|
||||
@@ -156,18 +156,3 @@ pub unsafe extern "C" fn wasmer_last_error_message(
|
||||
|
||||
error_message.len() as c_int + 1
|
||||
}
|
||||
|
||||
/// Rust type to represent a C API error.
|
||||
#[derive(Debug)]
|
||||
pub struct CApiError {
|
||||
/// The error message.
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl Display for CApiError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", &self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for CApiError {}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
//! This resolver is used in the Wasm-C-API as the imports are provided
|
||||
//! by index and not by module and name.
|
||||
|
||||
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
|
||||
use std::iter::FromIterator;
|
||||
use wasmer_api::{Export, Exportable, Extern, Resolver};
|
||||
|
||||
@@ -26,16 +25,10 @@ impl Resolver for OrderedResolver {
|
||||
|
||||
impl FromIterator<Extern> for OrderedResolver {
|
||||
fn from_iter<I: IntoIterator<Item = Extern>>(iter: I) -> Self {
|
||||
OrderedResolver {
|
||||
externs: iter.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromParallelIterator<Extern> for OrderedResolver {
|
||||
fn from_par_iter<I: IntoParallelIterator<Item = Extern>>(iter: I) -> Self {
|
||||
OrderedResolver {
|
||||
externs: iter.into_par_iter().collect(),
|
||||
let mut externs = Vec::new();
|
||||
for extern_ in iter {
|
||||
externs.push(extern_);
|
||||
}
|
||||
OrderedResolver { externs }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub use super::unstable::middlewares::wasm_config_push_middleware;
|
||||
#[cfg(feature = "middlewares")]
|
||||
use super::unstable::middlewares::wasmer_middleware_t;
|
||||
use super::unstable::target_lexicon::wasmer_target_t;
|
||||
use crate::error::{update_last_error, CApiError};
|
||||
use crate::error::update_last_error;
|
||||
use cfg_if::cfg_if;
|
||||
use std::sync::Arc;
|
||||
use wasmer_api::Engine;
|
||||
@@ -433,13 +433,8 @@ pub extern "C" fn wasm_engine_new_with_config(
|
||||
config: Option<Box<wasm_config_t>>,
|
||||
) -> Option<Box<wasm_engine_t>> {
|
||||
#[allow(dead_code)]
|
||||
fn return_with_error<M>(msg: M) -> Option<Box<wasm_engine_t>>
|
||||
where
|
||||
M: ToString,
|
||||
{
|
||||
update_last_error(CApiError {
|
||||
msg: msg.to_string(),
|
||||
});
|
||||
fn return_with_error(msg: &str) -> Option<Box<wasm_engine_t>> {
|
||||
update_last_error(msg);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
71
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
71
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
@@ -5,6 +5,7 @@ use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
|
||||
use super::CApiExternTag;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::Arc;
|
||||
use wasmer_api::{Function, RuntimeError, Val};
|
||||
|
||||
@@ -27,16 +28,16 @@ impl wasm_func_t {
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type wasm_func_callback_t = unsafe extern "C" fn(
|
||||
args: *const wasm_val_vec_t,
|
||||
results: *mut wasm_val_vec_t,
|
||||
) -> *mut wasm_trap_t;
|
||||
args: &wasm_val_vec_t,
|
||||
results: &mut wasm_val_vec_t,
|
||||
) -> Option<Box<wasm_trap_t>>;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
|
||||
env: *mut c_void,
|
||||
args: *const wasm_val_vec_t,
|
||||
results: *mut wasm_val_vec_t,
|
||||
) -> *mut wasm_trap_t;
|
||||
args: &wasm_val_vec_t,
|
||||
results: &mut wasm_val_vec_t,
|
||||
) -> Option<Box<wasm_trap_t>>;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void);
|
||||
@@ -72,15 +73,12 @@ pub unsafe extern "C" fn wasm_func_new(
|
||||
|
||||
let trap = callback(&processed_args, &mut results);
|
||||
|
||||
if !trap.is_null() {
|
||||
let trap: Box<wasm_trap_t> = Box::from_raw(trap);
|
||||
|
||||
if let Some(trap) = trap {
|
||||
return Err(trap.inner);
|
||||
}
|
||||
|
||||
let processed_results = results
|
||||
.into_slice()
|
||||
.expect("Failed to convert `results` into a slice")
|
||||
.take()
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<Val>, _>>()
|
||||
@@ -124,15 +122,11 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
|
||||
|
||||
impl Drop for WrapperEnv {
|
||||
fn drop(&mut self) {
|
||||
if let Some(env_finalizer) =
|
||||
Arc::get_mut(&mut self.env_finalizer).and_then(Option::take)
|
||||
{
|
||||
if !self.env.is_null() {
|
||||
if let Some(env_finalizer) = *self.env_finalizer {
|
||||
unsafe { (env_finalizer)(self.env as _) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let trampoline = move |env: &WrapperEnv, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
||||
let processed_args: wasm_val_vec_t = args
|
||||
@@ -153,15 +147,12 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
|
||||
|
||||
let trap = callback(env.env, &processed_args, &mut results);
|
||||
|
||||
if !trap.is_null() {
|
||||
let trap: Box<wasm_trap_t> = Box::from_raw(trap);
|
||||
|
||||
if let Some(trap) = trap {
|
||||
return Err(trap.inner);
|
||||
}
|
||||
|
||||
let processed_results = results
|
||||
.into_slice()
|
||||
.expect("Failed to convert `results` into a slice")
|
||||
.take()
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<Val>, _>>()
|
||||
@@ -201,39 +192,21 @@ pub unsafe extern "C" fn wasm_func_call(
|
||||
let args = args?;
|
||||
|
||||
let params = args
|
||||
.into_slice()
|
||||
.map(|slice| {
|
||||
slice
|
||||
.into_iter()
|
||||
.as_slice()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<Val>, _>>()
|
||||
.expect("Arguments conversion failed")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
.expect("Arguments conversion failed");
|
||||
|
||||
match func.inner.call(¶ms) {
|
||||
Ok(wasm_results) => {
|
||||
let vals = wasm_results
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<wasm_val_t>, _>>()
|
||||
.expect("Results conversion failed");
|
||||
|
||||
// `results` is an uninitialized vector. Set a new value.
|
||||
if results.is_uninitialized() {
|
||||
*results = vals.into();
|
||||
}
|
||||
// `results` is an initialized but empty vector. Fill it
|
||||
// item per item.
|
||||
else {
|
||||
let slice = results
|
||||
.into_slice_mut()
|
||||
.expect("`wasm_func_call`, results' size is greater than 0 but data is NULL");
|
||||
|
||||
for (result, value) in slice.iter_mut().zip(vals.iter()) {
|
||||
(*result).kind = value.kind;
|
||||
(*result).of = value.of;
|
||||
}
|
||||
for (slot, val) in results
|
||||
.as_uninit_slice()
|
||||
.iter_mut()
|
||||
.zip(wasm_results.into_iter())
|
||||
{
|
||||
*slot = MaybeUninit::new(val.try_into().expect("Results conversion failed"));
|
||||
}
|
||||
|
||||
None
|
||||
|
||||
1
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
1
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
@@ -48,7 +48,6 @@ pub unsafe extern "C" fn wasm_global_new(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>) {}
|
||||
|
||||
// TODO: figure out if these should be deep or shallow copies
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> {
|
||||
// do shallow copy
|
||||
|
||||
1
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
1
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
@@ -38,7 +38,6 @@ pub unsafe extern "C" fn wasm_memory_new(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memory_delete(_memory: Option<Box<wasm_memory_t>>) {}
|
||||
|
||||
// TODO: figure out if these should be deep or shallow copies
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> {
|
||||
// do shallow copy
|
||||
|
||||
26
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
26
lib/c-api/src/wasm_c_api/externals/mod.rs
vendored
@@ -6,7 +6,7 @@ mod table;
|
||||
pub use function::*;
|
||||
pub use global::*;
|
||||
pub use memory::*;
|
||||
use std::mem;
|
||||
use std::mem::{self, ManuallyDrop};
|
||||
pub use table::*;
|
||||
use wasmer_api::{Extern, ExternType};
|
||||
|
||||
@@ -150,13 +150,23 @@ impl From<Extern> for wasm_extern_t {
|
||||
}
|
||||
|
||||
impl From<wasm_extern_t> for Extern {
|
||||
fn from(other: wasm_extern_t) -> Self {
|
||||
match other.get_tag() {
|
||||
CApiExternTag::Function => unsafe { (&*other.inner.function.inner).clone().into() },
|
||||
CApiExternTag::Memory => unsafe { (&*other.inner.memory.inner).clone().into() },
|
||||
CApiExternTag::Table => unsafe { (&*other.inner.table.inner).clone().into() },
|
||||
CApiExternTag::Global => unsafe { (&*other.inner.global.inner).clone().into() },
|
||||
}
|
||||
fn from(mut other: wasm_extern_t) -> Self {
|
||||
let out = match other.get_tag() {
|
||||
CApiExternTag::Function => unsafe {
|
||||
(*ManuallyDrop::take(&mut other.inner.function).inner).into()
|
||||
},
|
||||
CApiExternTag::Memory => unsafe {
|
||||
(*ManuallyDrop::take(&mut other.inner.memory).inner).into()
|
||||
},
|
||||
CApiExternTag::Table => unsafe {
|
||||
(*ManuallyDrop::take(&mut other.inner.table).inner).into()
|
||||
},
|
||||
CApiExternTag::Global => unsafe {
|
||||
(*ManuallyDrop::take(&mut other.inner.global).inner).into()
|
||||
},
|
||||
};
|
||||
mem::forget(other);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use super::externals::{wasm_extern_t, wasm_extern_vec_t};
|
||||
use super::externals::wasm_extern_vec_t;
|
||||
use super::module::wasm_module_t;
|
||||
use super::store::wasm_store_t;
|
||||
use super::trap::wasm_trap_t;
|
||||
use crate::ordered_resolver::OrderedResolver;
|
||||
use rayon::prelude::*;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use wasmer_api::{Extern, Instance, InstantiationError};
|
||||
|
||||
@@ -42,7 +40,7 @@ pub unsafe extern "C" fn wasm_instance_new(
|
||||
_store: Option<&wasm_store_t>,
|
||||
module: Option<&wasm_module_t>,
|
||||
imports: Option<&wasm_extern_vec_t>,
|
||||
trap: *mut *mut wasm_trap_t,
|
||||
trap: Option<&mut *mut wasm_trap_t>,
|
||||
) -> Option<Box<wasm_instance_t>> {
|
||||
let module = module?;
|
||||
let imports = imports?;
|
||||
@@ -51,10 +49,9 @@ pub unsafe extern "C" fn wasm_instance_new(
|
||||
let module_imports = wasm_module.imports();
|
||||
let module_import_count = module_imports.len();
|
||||
let resolver: OrderedResolver = imports
|
||||
.into_slice()
|
||||
.map(|imports| imports.par_iter())
|
||||
.unwrap_or_else(|| [].par_iter())
|
||||
.map(|imp| Extern::from((&**imp).clone()))
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|imp| Extern::from(imp.as_ref().unwrap().as_ref().clone()))
|
||||
.take(module_import_count)
|
||||
.collect();
|
||||
|
||||
@@ -68,8 +65,16 @@ pub unsafe extern "C" fn wasm_instance_new(
|
||||
}
|
||||
|
||||
Err(InstantiationError::Start(runtime_error)) => {
|
||||
if let Some(trap) = trap {
|
||||
let this_trap: Box<wasm_trap_t> = Box::new(runtime_error.into());
|
||||
*trap = Box::into_raw(this_trap);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
Err(e @ InstantiationError::CpuFeature(_)) => {
|
||||
crate::error::update_last_error(e);
|
||||
|
||||
return None;
|
||||
}
|
||||
@@ -182,17 +187,13 @@ pub unsafe extern "C" fn wasm_instance_exports(
|
||||
out: &mut wasm_extern_vec_t,
|
||||
) {
|
||||
let instance = &instance.inner;
|
||||
let mut extern_vec = instance
|
||||
let extern_vec = instance
|
||||
.exports
|
||||
.iter()
|
||||
.map(|(_name, r#extern)| Box::into_raw(Box::new(r#extern.clone().into())))
|
||||
.collect::<Vec<*mut wasm_extern_t>>();
|
||||
extern_vec.shrink_to_fit();
|
||||
.map(|(_name, r#extern)| Some(Box::new(r#extern.clone().into())))
|
||||
.collect();
|
||||
|
||||
out.size = extern_vec.len();
|
||||
out.data = extern_vec.as_mut_ptr();
|
||||
|
||||
mem::forget(extern_vec);
|
||||
out.set_buffer(extern_vec);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,13 +1,121 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! wasm_declare_vec_inner {
|
||||
($name:ident) => {
|
||||
wasm_declare_vec_inner!($name, wasm);
|
||||
};
|
||||
(
|
||||
name: $name:ident,
|
||||
ty: $elem_ty:ty,
|
||||
c_ty: $c_ty:expr,
|
||||
c_val: $c_val:expr,
|
||||
new: $new:ident,
|
||||
empty: $empty:ident,
|
||||
uninit: $uninit:ident,
|
||||
copy: $copy:ident,
|
||||
delete: $delete:ident,
|
||||
) => {
|
||||
#[doc = concat!("Represents a vector of `", $c_ty, "`.
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
paste::paste! {
|
||||
#[doc = "Creates an empty vector of [`" $prefix "_" $name "_t`].
|
||||
Read the documentation of [`", $c_ty, "`] to see more concrete examples.
|
||||
|
||||
# Example
|
||||
|
||||
```rust
|
||||
# use inline_c::assert_c;
|
||||
# fn main() {
|
||||
# (assert_c! {
|
||||
# #include \"tests/wasmer.h\"
|
||||
#
|
||||
void example(", $c_ty, " x, ", $c_ty, " y) {
|
||||
// Create a vector of 2 `", $c_ty, "`.
|
||||
", $c_ty, " items[2] = {x, y};
|
||||
|
||||
", stringify!($name), " vector;
|
||||
", stringify!($new), "(&vector, 2, items);
|
||||
|
||||
// Check that it contains 2 items.
|
||||
assert(vector.size == 2);
|
||||
|
||||
// Free it.
|
||||
", stringify!($delete), "(&vector);
|
||||
}
|
||||
#
|
||||
# int main() { example(", $c_val, ", ", $c_val, "); return 0; }
|
||||
# })
|
||||
# .success();
|
||||
# }
|
||||
```")]
|
||||
#[repr(C)]
|
||||
pub struct $name {
|
||||
pub size: usize,
|
||||
pub data: *mut $elem_ty,
|
||||
}
|
||||
|
||||
impl $name {
|
||||
// Note that this does not free any existing buffer.
|
||||
pub fn set_buffer(&mut self, buffer: Vec<$elem_ty>) {
|
||||
let mut vec = buffer.into_boxed_slice();
|
||||
self.size = vec.len();
|
||||
self.data = vec.as_mut_ptr();
|
||||
std::mem::forget(vec);
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[$elem_ty] {
|
||||
// Note that we're careful to not create a slice with a null
|
||||
// pointer as the data pointer, since that isn't defined
|
||||
// behavior in Rust.
|
||||
if self.size == 0 {
|
||||
&[]
|
||||
} else {
|
||||
assert!(!self.data.is_null());
|
||||
unsafe { std::slice::from_raw_parts(self.data, self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_uninit_slice(&mut self) -> &mut [std::mem::MaybeUninit<$elem_ty>] {
|
||||
// Note that we're careful to not create a slice with a null
|
||||
// pointer as the data pointer, since that isn't defined
|
||||
// behavior in Rust.
|
||||
if self.size == 0 {
|
||||
&mut []
|
||||
} else {
|
||||
assert!(!self.data.is_null());
|
||||
unsafe { std::slice::from_raw_parts_mut(self.data as _, self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Vec<$elem_ty> {
|
||||
if self.data.is_null() {
|
||||
return Vec::new();
|
||||
}
|
||||
let vec = unsafe { Vec::from_raw_parts(self.data, self.size, self.size) };
|
||||
self.data = std::ptr::null_mut();
|
||||
self.size = 0;
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<$elem_ty>> for $name {
|
||||
fn from(vec: Vec<$elem_ty>) -> Self {
|
||||
let mut vec = vec.into_boxed_slice();
|
||||
let result = $name {
|
||||
size: vec.len(),
|
||||
data: vec.as_mut_ptr(),
|
||||
};
|
||||
std::mem::forget(vec);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
self.as_slice().to_vec().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $name {
|
||||
fn drop(&mut self) {
|
||||
drop(self.take());
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = concat!("Creates an empty vector of [`", $c_ty, "`].
|
||||
|
||||
# Example
|
||||
|
||||
@@ -18,31 +126,89 @@ macro_rules! wasm_declare_vec_inner {
|
||||
# #include \"tests/wasmer.h\"
|
||||
#
|
||||
int main() {
|
||||
// Creates an empty vector of `" $prefix "_" $name "_t`.
|
||||
" $prefix "_" $name "_vec_t vector;
|
||||
" $prefix "_" $name "_vec_new_empty(&vector);
|
||||
// Creates an empty vector of `", $c_ty, "`.
|
||||
", stringify!($name), " vector;
|
||||
", stringify!($empty), "(&vector);
|
||||
|
||||
// Check that it is empty.
|
||||
assert(vector.size == 0);
|
||||
|
||||
// Free it.
|
||||
" $prefix "_" $name "_vec_delete(&vector);
|
||||
", stringify!($delete), "(&vector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
# })
|
||||
# .success();
|
||||
# }
|
||||
```"]
|
||||
```")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_empty>](out: *mut [<$prefix _ $name _vec_t>]) {
|
||||
// TODO: actually implement this
|
||||
[<$prefix _ $name _vec_new_uninitialized>](out, 0);
|
||||
pub extern "C" fn $empty(out: &mut $name) {
|
||||
out.size = 0;
|
||||
out.data = std::ptr::null_mut();
|
||||
}
|
||||
|
||||
#[doc = concat!("Creates a new uninitialized vector of [`", $c_ty, "`].
|
||||
|
||||
# Example
|
||||
|
||||
```rust
|
||||
# use inline_c::assert_c;
|
||||
# fn main() {
|
||||
# (assert_c! {
|
||||
# #include \"tests/wasmer.h\"
|
||||
#
|
||||
int main() {
|
||||
// Creates an empty vector of `", $c_ty, "`.
|
||||
", stringify!($name), " vector;
|
||||
", stringify!($uninit), "(&vector, 3);
|
||||
|
||||
// Check that it contains 3 items.
|
||||
assert(vector.size == 3);
|
||||
|
||||
// Free it.
|
||||
", stringify!($delete), "(&vector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
# })
|
||||
# .success();
|
||||
# }
|
||||
```")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn $uninit(out: &mut $name, size: usize) {
|
||||
out.set_buffer(vec![Default::default(); size]);
|
||||
}
|
||||
|
||||
#[doc = concat!("Creates a new vector of [`", $c_ty, "`].
|
||||
|
||||
# Example
|
||||
|
||||
See the [`", stringify!($name), "`] type to get an example.")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $new(out: &mut $name, size: usize, ptr: *const $elem_ty) {
|
||||
let vec = (0..size).map(|i| ptr.add(i).read()).collect();
|
||||
out.set_buffer(vec);
|
||||
}
|
||||
|
||||
#[doc = concat!("Performs a deep copy of a vector of [`", $c_ty, "`].")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn $copy(out: &mut $name, src: &$name) {
|
||||
out.set_buffer(src.as_slice().to_vec());
|
||||
}
|
||||
|
||||
#[doc = concat!("Deletes a vector of [`", $c_ty, "`].
|
||||
|
||||
# Example
|
||||
|
||||
See the [`", stringify!($name), "`] type to get an example.")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn $delete(out: &mut $name) {
|
||||
out.take();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! wasm_declare_vec {
|
||||
($name:ident) => {
|
||||
wasm_declare_vec!($name, wasm);
|
||||
@@ -50,218 +216,25 @@ macro_rules! wasm_declare_vec {
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
paste::paste! {
|
||||
#[doc = "Represents a vector of `" $prefix "_" $name "_t`.
|
||||
|
||||
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples.
|
||||
|
||||
# Example
|
||||
|
||||
```rust
|
||||
# use inline_c::assert_c;
|
||||
# fn main() {
|
||||
# (assert_c! {
|
||||
# #include \"tests/wasmer.h\"
|
||||
#
|
||||
int main() {
|
||||
// Create a vector of 2 `" $prefix "_" $name "_t`.
|
||||
" $prefix "_" $name "_t x;
|
||||
" $prefix "_" $name "_t y;
|
||||
" $prefix "_" $name "_t* items[2] = {&x, &y};
|
||||
|
||||
" $prefix "_" $name "_vec_t vector;
|
||||
" $prefix "_" $name "_vec_new(&vector, 2, (" $prefix "_" $name "_t*) items);
|
||||
|
||||
// Check that it contains 2 items.
|
||||
assert(vector.size == 2);
|
||||
|
||||
// Free it.
|
||||
" $prefix "_" $name "_vec_delete(&vector);
|
||||
}
|
||||
# })
|
||||
# .success();
|
||||
# }
|
||||
```"]
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct [<$prefix _ $name _vec_t>] {
|
||||
pub size: usize,
|
||||
pub data: *mut [<$prefix _ $name _t>],
|
||||
wasm_declare_vec_inner!(
|
||||
name: [<$prefix _ $name _vec_t>],
|
||||
ty: [<$prefix _ $name _t>],
|
||||
c_ty: stringify!([<$prefix _ $name _t>]),
|
||||
c_val: concat!("({ ",
|
||||
stringify!([<$prefix _ $name _t>]), " foo;\n",
|
||||
"memset(&foo, 0, sizeof(foo));\n",
|
||||
"foo;\n",
|
||||
"})"),
|
||||
new: [<$prefix _ $name _vec_new>],
|
||||
empty: [<$prefix _ $name _vec_new_empty>],
|
||||
uninit: [<$prefix _ $name _vec_new_uninitialized>],
|
||||
copy: [<$prefix _ $name _vec_copy>],
|
||||
delete: [<$prefix _ $name _vec_delete>],
|
||||
);
|
||||
}
|
||||
|
||||
impl Clone for [<$prefix _ $name _vec_t>] {
|
||||
fn clone(&self) -> Self {
|
||||
if self.data.is_null() {
|
||||
return Self {
|
||||
size: self.size,
|
||||
data: ::std::ptr::null_mut(),
|
||||
};
|
||||
}
|
||||
let data =
|
||||
unsafe {
|
||||
let vec = Vec::from_raw_parts(self.data, self.size, self.size);
|
||||
let mut vec_copy = vec.clone().into_boxed_slice();
|
||||
let new_ptr = vec_copy.as_mut_ptr();
|
||||
|
||||
::std::mem::forget(vec);
|
||||
::std::mem::forget(vec_copy);
|
||||
|
||||
new_ptr
|
||||
};
|
||||
|
||||
Self {
|
||||
size: self.size,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Vec<[<$prefix _ $name _t>]>> for [<$prefix _ $name _vec_t>] {
|
||||
fn from(mut vec: Vec<[<$prefix _ $name _t>]>) -> Self {
|
||||
vec.shrink_to_fit();
|
||||
|
||||
let length = vec.len();
|
||||
let pointer = vec.as_mut_ptr();
|
||||
|
||||
::std::mem::forget(vec);
|
||||
|
||||
Self {
|
||||
size: length,
|
||||
data: pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Into<[<$prefix _ $name _t>]> + Clone> From<&'a [T]> for [<$prefix _ $name _vec_t>] {
|
||||
fn from(other: &'a [T]) -> Self {
|
||||
let size = other.len();
|
||||
let mut copied_data = other
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<[<$prefix _ $name _t>]>>()
|
||||
.into_boxed_slice();
|
||||
let data = copied_data.as_mut_ptr();
|
||||
::std::mem::forget(copied_data);
|
||||
|
||||
Self {
|
||||
size,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl [<$prefix _ $name _vec_t>] {
|
||||
pub unsafe fn into_slice(&self) -> Option<&[[<$prefix _ $name _t>]]>{
|
||||
if self.is_uninitialized() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(::std::slice::from_raw_parts(self.data, self.size))
|
||||
}
|
||||
|
||||
pub unsafe fn into_slice_mut(&mut self) -> Option<&mut [[<$prefix _ $name _t>]]>{
|
||||
if self.is_uninitialized() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(::std::slice::from_raw_parts_mut(self.data, self.size))
|
||||
}
|
||||
|
||||
pub fn is_uninitialized(&self) -> bool {
|
||||
self.data.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: investigate possible memory leak on `init` (owned pointer)
|
||||
#[doc = "Creates a new vector of [`" $prefix "_" $name "_t`].
|
||||
|
||||
# Example
|
||||
|
||||
See the [`" $prefix "_" $name "_vec_t`] type to get an example."]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_new>](out: *mut [<$prefix _ $name _vec_t>], length: usize, init: *mut [<$prefix _ $name _t>]) {
|
||||
let mut bytes: Vec<[<$prefix _ $name _t>]> = Vec::with_capacity(length);
|
||||
|
||||
for i in 0..length {
|
||||
bytes.push(::std::ptr::read(init.add(i)));
|
||||
}
|
||||
|
||||
let pointer = bytes.as_mut_ptr();
|
||||
debug_assert!(bytes.len() == bytes.capacity());
|
||||
|
||||
(*out).data = pointer;
|
||||
(*out).size = length;
|
||||
::std::mem::forget(bytes);
|
||||
}
|
||||
|
||||
#[doc = "Creates a new uninitialized vector of [`" $prefix "_" $name "_t`].
|
||||
|
||||
# Example
|
||||
|
||||
```rust
|
||||
# use inline_c::assert_c;
|
||||
# fn main() {
|
||||
# (assert_c! {
|
||||
# #include \"tests/wasmer.h\"
|
||||
#
|
||||
int main() {
|
||||
// Creates an empty vector of `" $prefix "_" $name "_t`.
|
||||
" $prefix "_" $name "_vec_t vector;
|
||||
" $prefix "_" $name "_vec_new_uninitialized(&vector, 3);
|
||||
|
||||
// Check that it contains 3 items.
|
||||
assert(vector.size == 3);
|
||||
|
||||
// Free it.
|
||||
" $prefix "_" $name "_vec_delete(&vector);
|
||||
}
|
||||
# })
|
||||
# .success();
|
||||
# }
|
||||
```"]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_uninitialized>](out: *mut [<$prefix _ $name _vec_t>], length: usize) {
|
||||
let mut bytes: Vec<[<$prefix _ $name _t>]> = Vec::with_capacity(length);
|
||||
let pointer = bytes.as_mut_ptr();
|
||||
|
||||
(*out).data = pointer;
|
||||
(*out).size = length;
|
||||
|
||||
::std::mem::forget(bytes);
|
||||
}
|
||||
|
||||
#[doc = "Performs a deep copy of a vector of [`" $prefix "_" $name "_t`]."]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_copy>](
|
||||
out_ptr: &mut [<$prefix _ $name _vec_t>],
|
||||
in_ptr: & [<wasm _$name _vec_t>])
|
||||
{
|
||||
*out_ptr = in_ptr.clone();
|
||||
}
|
||||
|
||||
#[doc = "Deletes a vector of [`" $prefix "_" $name "_t`].
|
||||
|
||||
# Example
|
||||
|
||||
See the [`" $prefix "_" $name "_vec_t`] type to get an example."]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_delete>](ptr: Option<&mut [<$prefix _ $name _vec_t>]>) {
|
||||
if let Some(vec) = ptr {
|
||||
if !vec.data.is_null() {
|
||||
Vec::from_raw_parts(vec.data, vec.size, vec.size);
|
||||
vec.data = ::std::ptr::null_mut();
|
||||
vec.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasm_declare_vec_inner!($name, $prefix);
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! wasm_declare_boxed_vec {
|
||||
($name:ident) => {
|
||||
wasm_declare_boxed_vec!($name, wasm);
|
||||
@@ -269,223 +242,60 @@ macro_rules! wasm_declare_boxed_vec {
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
paste::paste! {
|
||||
#[doc = "Represents a vector of `" $prefix "_" $name "_t`.
|
||||
|
||||
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples."]
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct [<$prefix _ $name _vec_t>] {
|
||||
pub size: usize,
|
||||
pub data: *mut *mut [<$prefix _ $name _t>],
|
||||
wasm_declare_vec_inner!(
|
||||
name: [<$prefix _ $name _vec_t>],
|
||||
ty: Option<Box<[<$prefix _ $name _t>]>>,
|
||||
c_ty: stringify!([<$prefix _ $name _t>] *),
|
||||
c_val: "NULL",
|
||||
new: [<$prefix _ $name _vec_new>],
|
||||
empty: [<$prefix _ $name _vec_new_empty>],
|
||||
uninit: [<$prefix _ $name _vec_new_uninitialized>],
|
||||
copy: [<$prefix _ $name _vec_copy>],
|
||||
delete: [<$prefix _ $name _vec_delete>],
|
||||
);
|
||||
}
|
||||
|
||||
impl Clone for [<$prefix _ $name _vec_t>] {
|
||||
fn clone(&self) -> Self {
|
||||
if self.data.is_null() {
|
||||
return Self {
|
||||
size: self.size,
|
||||
data: ::std::ptr::null_mut(),
|
||||
};
|
||||
}
|
||||
let data =
|
||||
unsafe {
|
||||
let data: *mut Option<Box<[<$prefix _ $name _t>]>> = self.data as _;
|
||||
let vec = Vec::from_raw_parts(data, self.size, self.size);
|
||||
let mut vec_copy = vec.clone().into_boxed_slice();
|
||||
let new_ptr = vec_copy.as_mut_ptr() as *mut *mut [<$prefix _ $name _t>];
|
||||
|
||||
::std::mem::forget(vec);
|
||||
::std::mem::forget(vec_copy);
|
||||
|
||||
new_ptr
|
||||
};
|
||||
|
||||
Self {
|
||||
size: self.size,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Vec<Box<[<$prefix _ $name _t>]>>> for [<$prefix _ $name _vec_t>] {
|
||||
fn from(other: Vec<Box<[<$prefix _ $name _t>]>>) -> Self {
|
||||
let boxed_slice: Box<[Box<[<$prefix _ $name _t>]>]> = other.into_boxed_slice();
|
||||
let mut boxed_slice: Box<[*mut [<$prefix _ $name _t>]]> = unsafe { ::std::mem::transmute(boxed_slice) };
|
||||
let size = boxed_slice.len();
|
||||
let data = boxed_slice.as_mut_ptr();
|
||||
|
||||
::std::mem::forget(boxed_slice);
|
||||
Self {
|
||||
size,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Into<[<$prefix _ $name _t>]> + Clone> From<&'a [T]> for [<$prefix _ $name _vec_t>] {
|
||||
fn from(other: &'a [T]) -> Self {
|
||||
let size = other.len();
|
||||
let mut copied_data = other
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.map(Box::into_raw)
|
||||
.collect::<Vec<*mut [<$prefix _ $name _t>]>>()
|
||||
.into_boxed_slice();
|
||||
let data = copied_data.as_mut_ptr();
|
||||
::std::mem::forget(copied_data);
|
||||
|
||||
Self {
|
||||
size,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do this properly
|
||||
impl [<$prefix _ $name _vec_t>] {
|
||||
pub unsafe fn into_slice(&self) -> Option<&[Box<[<$prefix _ $name _t>]>]>{
|
||||
if self.data.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let slice: &[*mut [<$prefix _ $name _t>]] = ::std::slice::from_raw_parts(self.data, self.size);
|
||||
let slice: &[Box<[<$prefix _ $name _t>]>] = ::std::mem::transmute(slice);
|
||||
Some(slice)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: investigate possible memory leak on `init` (owned pointer)
|
||||
#[doc = "Creates a new vector of [`" $prefix "_" $name "_t`]."]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_new>](out: *mut [<$prefix _ $name _vec_t>], length: usize, init: *const *mut [<$prefix _ $name _t>]) {
|
||||
let mut bytes: Vec<*mut [<$prefix _ $name _t>]> = Vec::with_capacity(length);
|
||||
|
||||
for i in 0..length {
|
||||
bytes.push(*init.add(i));
|
||||
}
|
||||
|
||||
let mut boxed_vec = bytes.into_boxed_slice();
|
||||
let pointer = boxed_vec.as_mut_ptr();
|
||||
|
||||
(*out).data = pointer;
|
||||
(*out).size = length;
|
||||
|
||||
::std::mem::forget(boxed_vec);
|
||||
}
|
||||
|
||||
#[doc = "Creates a new uninitialized vector of [`" $prefix "_" $name "_t`].
|
||||
|
||||
# Example
|
||||
|
||||
```rust
|
||||
# use inline_c::assert_c;
|
||||
# fn main() {
|
||||
# (assert_c! {
|
||||
# #include \"tests/wasmer.h\"
|
||||
#
|
||||
int main() {
|
||||
// Creates an empty vector of `" $prefix "_" $name "_t`.
|
||||
" $prefix "_" $name "_vec_t vector;
|
||||
" $prefix "_" $name "_vec_new_uninitialized(&vector, 3);
|
||||
|
||||
// Check that it contains 3 items.
|
||||
assert(vector.size == 3);
|
||||
|
||||
// Free it.
|
||||
" $prefix "_" $name "_vec_delete(&vector);
|
||||
}
|
||||
# })
|
||||
# .success();
|
||||
# }
|
||||
```"]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_uninitialized>](out: *mut [<$prefix _ $name _vec_t>], length: usize) {
|
||||
let mut bytes: Vec<*mut [<$prefix _ $name _t>]> = vec![::std::ptr::null_mut(); length];
|
||||
let pointer = bytes.as_mut_ptr();
|
||||
|
||||
(*out).data = pointer;
|
||||
(*out).size = length;
|
||||
|
||||
::std::mem::forget(bytes);
|
||||
}
|
||||
|
||||
#[doc = "Performs a deep copy of a vector of [`" $prefix "_" $name "_t`]."]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_copy>](
|
||||
out_ptr: &mut [<$prefix _ $name _vec_t>],
|
||||
in_ptr: & [<$prefix _ $name _vec_t>])
|
||||
{
|
||||
*out_ptr = in_ptr.clone();
|
||||
}
|
||||
|
||||
#[doc = "Deletes a vector of [`" $prefix "_" $name "_t`].
|
||||
|
||||
# Example
|
||||
|
||||
See the [`" $prefix "_" $name "_vec_t`] type to get an example."]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$prefix _ $name _vec_delete>](ptr: Option<&mut [<$prefix _ $name _vec_t>]>) {
|
||||
if let Some(vec) = ptr {
|
||||
if !vec.data.is_null() {
|
||||
let data = vec.data as *mut Option<Box<[<$prefix _ $name _t>]>>;
|
||||
let _data: Vec<Option<Box<[<$prefix _ $name _t>]>>> = Vec::from_raw_parts(data, vec.size, vec.size);
|
||||
|
||||
vec.data = ::std::ptr::null_mut();
|
||||
vec.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasm_declare_vec_inner!($name, $prefix);
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! wasm_declare_ref_base {
|
||||
macro_rules! wasm_impl_copy {
|
||||
($name:ident) => {
|
||||
wasm_declare_ref_base!($name, wasm);
|
||||
};
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
wasm_declare_own!($name, $prefix);
|
||||
|
||||
paste::paste! {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn [<$prefix _ $name _copy>](_arg: *const [<$prefix _ $name _t>]) -> *mut [<$prefix _ $name _t>] {
|
||||
todo!("in generated declare ref base");
|
||||
//ptr::null_mut()
|
||||
}
|
||||
|
||||
// TODO: finish this...
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! wasm_declare_own {
|
||||
($name:ident) => {
|
||||
wasm_declare_own!($name, $prefix);
|
||||
wasm_impl_copy!($name, wasm);
|
||||
};
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
paste::paste! {
|
||||
#[repr(C)]
|
||||
pub struct [<$prefix _ $name _t>] {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn [<$prefix _ $name _delete>](_arg: *mut [<$prefix _ $name _t>]) {
|
||||
todo!("in generated delete")
|
||||
pub extern "C" fn [<$prefix _ $name _copy>](src: Option<&[<$prefix _ $name _t>]>) -> Option<Box<[<$prefix _ $name _t>]>> {
|
||||
Some(Box::new(src?.clone()))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! wasm_impl_delete {
|
||||
($name:ident) => {
|
||||
wasm_impl_delete!($name, wasm);
|
||||
};
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
paste::paste! {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn [<$prefix _ $name _delete>](_: Option<Box<[<$prefix _ $name _t>]>>) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wasm_impl_copy_delete {
|
||||
($name:ident) => {
|
||||
wasm_impl_copy_delete!($name, wasm);
|
||||
};
|
||||
|
||||
($name:ident, $prefix:ident) => {
|
||||
wasm_impl_copy!($name, $prefix);
|
||||
wasm_impl_delete!($name, $prefix);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! c_try {
|
||||
($expr:expr; otherwise $return:expr) => {{
|
||||
let res: Result<_, _> = $expr;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
/// Private Rust macros.
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
mod macros;
|
||||
|
||||
/// An engine drives the compilation and the runtime.
|
||||
///
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use super::store::wasm_store_t;
|
||||
use super::types::{
|
||||
wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t,
|
||||
wasm_importtype_vec_t,
|
||||
};
|
||||
use crate::error::{update_last_error, CApiError};
|
||||
use super::types::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t};
|
||||
use crate::error::update_last_error;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::Arc;
|
||||
use wasmer_api::Module;
|
||||
@@ -36,8 +33,7 @@ pub unsafe extern "C" fn wasm_module_new(
|
||||
let store = store?;
|
||||
let bytes = bytes?;
|
||||
|
||||
let bytes = bytes.into_slice()?;
|
||||
let module = c_try!(Module::from_binary(&store.inner, bytes));
|
||||
let module = c_try!(Module::from_binary(&store.inner, bytes.as_slice()));
|
||||
|
||||
Some(Box::new(wasm_module_t {
|
||||
inner: Arc::new(module),
|
||||
@@ -107,12 +103,7 @@ pub unsafe extern "C" fn wasm_module_validate(
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let bytes = match bytes.into_slice() {
|
||||
Some(bytes) => bytes,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
if let Err(error) = Module::validate(&store.inner, bytes) {
|
||||
if let Err(error) = Module::validate(&store.inner, bytes.as_slice()) {
|
||||
update_last_error(error);
|
||||
|
||||
false
|
||||
@@ -238,11 +229,10 @@ pub unsafe extern "C" fn wasm_module_exports(
|
||||
let exports = module
|
||||
.inner
|
||||
.exports()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.collect::<Vec<Box<wasm_exporttype_t>>>();
|
||||
.map(|export| Some(Box::new(export.into())))
|
||||
.collect();
|
||||
|
||||
*out = exports.into();
|
||||
out.set_buffer(exports);
|
||||
}
|
||||
|
||||
/// Returns an array of the imported types in the module.
|
||||
@@ -379,11 +369,10 @@ pub unsafe extern "C" fn wasm_module_imports(
|
||||
let imports = module
|
||||
.inner
|
||||
.imports()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.collect::<Vec<Box<wasm_importtype_t>>>();
|
||||
.map(|import| Some(Box::new(import.into())))
|
||||
.collect();
|
||||
|
||||
*out = imports.into();
|
||||
out.set_buffer(imports);
|
||||
}
|
||||
|
||||
/// Deserializes a serialized module binary into a `wasm_module_t`.
|
||||
@@ -472,21 +461,11 @@ pub unsafe extern "C" fn wasm_module_imports(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_module_deserialize(
|
||||
store: &wasm_store_t,
|
||||
bytes: *const wasm_byte_vec_t,
|
||||
bytes: Option<&wasm_byte_vec_t>,
|
||||
) -> Option<NonNull<wasm_module_t>> {
|
||||
// TODO: read config from store and use that to decide which compiler to use
|
||||
let bytes = bytes?;
|
||||
|
||||
let byte_slice = if bytes.is_null() || (&*bytes).into_slice().is_none() {
|
||||
update_last_error(CApiError {
|
||||
msg: "`bytes` is null or represents an empty slice".to_string(),
|
||||
});
|
||||
|
||||
return None;
|
||||
} else {
|
||||
(&*bytes).into_slice().unwrap()
|
||||
};
|
||||
|
||||
let module = c_try!(Module::deserialize(&store.inner, byte_slice));
|
||||
let module = c_try!(Module::deserialize(&store.inner, bytes.as_slice()));
|
||||
|
||||
Some(NonNull::new_unchecked(Box::into_raw(Box::new(
|
||||
wasm_module_t {
|
||||
@@ -503,10 +482,7 @@ pub unsafe extern "C" fn wasm_module_deserialize(
|
||||
///
|
||||
/// See [`wasm_module_deserialize`].
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_module_serialize(
|
||||
module: &wasm_module_t,
|
||||
out_ptr: &mut wasm_byte_vec_t,
|
||||
) {
|
||||
pub unsafe extern "C" fn wasm_module_serialize(module: &wasm_module_t, out: &mut wasm_byte_vec_t) {
|
||||
let byte_vec = match module.inner.serialize() {
|
||||
Ok(byte_vec) => byte_vec,
|
||||
Err(err) => {
|
||||
@@ -514,7 +490,7 @@ pub unsafe extern "C" fn wasm_module_serialize(
|
||||
return;
|
||||
}
|
||||
};
|
||||
*out_ptr = byte_vec.into();
|
||||
out.set_buffer(byte_vec);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -28,7 +28,7 @@ pub unsafe extern "C" fn wasm_trap_new(
|
||||
_store: &mut wasm_store_t,
|
||||
message: &wasm_message_t,
|
||||
) -> Option<Box<wasm_trap_t>> {
|
||||
let message_bytes = message.into_slice()?;
|
||||
let message_bytes = message.as_slice();
|
||||
|
||||
// The trap message is typed with `wasm_message_t` which is a
|
||||
// typeref to `wasm_name_t` with the exception that it's a
|
||||
@@ -117,10 +117,7 @@ pub unsafe extern "C" fn wasm_trap_message(
|
||||
let mut byte_vec = message.into_bytes();
|
||||
byte_vec.push(0);
|
||||
|
||||
let byte_vec: wasm_byte_vec_t = byte_vec.into();
|
||||
|
||||
out.size = byte_vec.size;
|
||||
out.data = byte_vec.data;
|
||||
out.set_buffer(byte_vec);
|
||||
}
|
||||
|
||||
/// Gets the origin frame attached to the trap.
|
||||
@@ -137,10 +134,12 @@ pub unsafe extern "C" fn wasm_trap_trace(
|
||||
out: &mut wasm_frame_vec_t,
|
||||
) {
|
||||
let frames = trap.inner.trace();
|
||||
let frame_vec: wasm_frame_vec_t = frames.into();
|
||||
|
||||
out.size = frame_vec.size;
|
||||
out.data = frame_vec.data;
|
||||
out.set_buffer(
|
||||
frames
|
||||
.iter()
|
||||
.map(|frame| Some(Box::new(frame.into())))
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,40 +1,37 @@
|
||||
use super::{owned_wasm_name_t, wasm_externtype_t, wasm_name_t};
|
||||
use super::{wasm_externtype_t, wasm_name_t};
|
||||
use wasmer_api::ExportType;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasm_exporttype_t {
|
||||
name: owned_wasm_name_t,
|
||||
extern_type: Box<wasm_externtype_t>,
|
||||
name: wasm_name_t,
|
||||
extern_type: wasm_externtype_t,
|
||||
}
|
||||
|
||||
wasm_declare_boxed_vec!(exporttype);
|
||||
wasm_impl_copy_delete!(exporttype);
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_exporttype_new(
|
||||
name: Option<&wasm_name_t>,
|
||||
extern_type: Option<Box<wasm_externtype_t>>,
|
||||
) -> Option<Box<wasm_exporttype_t>> {
|
||||
let name = unsafe { owned_wasm_name_t::new(name?) };
|
||||
Some(Box::new(wasm_exporttype_t {
|
||||
name,
|
||||
extern_type: extern_type?,
|
||||
}))
|
||||
name: &wasm_name_t,
|
||||
extern_type: Box<wasm_externtype_t>,
|
||||
) -> Box<wasm_exporttype_t> {
|
||||
Box::new(wasm_exporttype_t {
|
||||
name: name.clone(),
|
||||
extern_type: *extern_type,
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_exporttype_name(export_type: &wasm_exporttype_t) -> &wasm_name_t {
|
||||
export_type.name.as_ref()
|
||||
&export_type.name
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_exporttype_type(export_type: &wasm_exporttype_t) -> &wasm_externtype_t {
|
||||
export_type.extern_type.as_ref()
|
||||
&export_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_exporttype_delete(_export_type: Option<Box<wasm_exporttype_t>>) {}
|
||||
|
||||
impl From<ExportType> for wasm_exporttype_t {
|
||||
fn from(other: ExportType) -> Self {
|
||||
(&other).into()
|
||||
@@ -43,8 +40,8 @@ impl From<ExportType> for wasm_exporttype_t {
|
||||
|
||||
impl From<&ExportType> for wasm_exporttype_t {
|
||||
fn from(other: &ExportType) -> Self {
|
||||
let name: owned_wasm_name_t = other.name().to_string().into();
|
||||
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into());
|
||||
let name: wasm_name_t = other.name().to_string().into();
|
||||
let extern_type: wasm_externtype_t = other.ty().into();
|
||||
|
||||
wasm_exporttype_t { name, extern_type }
|
||||
}
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
use super::{wasm_externtype_t, wasm_valtype_vec_delete, wasm_valtype_vec_t, WasmExternType};
|
||||
use super::{wasm_externtype_t, wasm_valtype_vec_t, WasmExternType};
|
||||
use std::fmt;
|
||||
use wasmer_api::{ExternType, FunctionType, ValType};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WasmFunctionType {
|
||||
pub(crate) function_type: FunctionType,
|
||||
params: Box<wasm_valtype_vec_t>,
|
||||
results: Box<wasm_valtype_vec_t>,
|
||||
params: wasm_valtype_vec_t,
|
||||
results: wasm_valtype_vec_t,
|
||||
}
|
||||
|
||||
impl WasmFunctionType {
|
||||
pub(crate) fn new(function_type: FunctionType) -> Self {
|
||||
let params: Box<wasm_valtype_vec_t> = Box::new(function_type.params().into());
|
||||
let results: Box<wasm_valtype_vec_t> = Box::new(function_type.results().into());
|
||||
let params: Vec<_> = function_type
|
||||
.params()
|
||||
.iter()
|
||||
.map(|&valtype| Some(Box::new(valtype.into())))
|
||||
.collect();
|
||||
let results: Vec<_> = function_type
|
||||
.results()
|
||||
.iter()
|
||||
.map(|&valtype| Some(Box::new(valtype.into())))
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
function_type,
|
||||
params,
|
||||
results,
|
||||
params: params.into(),
|
||||
results: results.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +35,12 @@ impl Clone for WasmFunctionType {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for WasmFunctionType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.function_type.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(transparent)]
|
||||
@@ -52,6 +66,7 @@ impl wasm_functype_t {
|
||||
}
|
||||
|
||||
wasm_declare_boxed_vec!(functype);
|
||||
wasm_impl_copy_delete!(functype);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_new(
|
||||
@@ -62,44 +77,29 @@ pub unsafe extern "C" fn wasm_functype_new(
|
||||
let results = results?;
|
||||
|
||||
let params_as_valtype: Vec<ValType> = params
|
||||
.into_slice()?
|
||||
.take()
|
||||
.into_iter()
|
||||
.map(|val| val.as_ref().into())
|
||||
.map(|val| val.as_ref().unwrap().as_ref().into())
|
||||
.collect::<Vec<_>>();
|
||||
let results_as_valtype: Vec<ValType> = results
|
||||
.into_slice()?
|
||||
.iter()
|
||||
.map(|val| val.as_ref().into())
|
||||
.take()
|
||||
.into_iter()
|
||||
.map(|val| val.as_ref().unwrap().as_ref().into())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
wasm_valtype_vec_delete(Some(params));
|
||||
wasm_valtype_vec_delete(Some(results));
|
||||
|
||||
Some(Box::new(wasm_functype_t::new(FunctionType::new(
|
||||
params_as_valtype,
|
||||
results_as_valtype,
|
||||
))))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_delete(_function_type: Option<Box<wasm_functype_t>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_copy(
|
||||
function_type: Option<&wasm_functype_t>,
|
||||
) -> Option<Box<wasm_functype_t>> {
|
||||
let function_type = function_type?;
|
||||
|
||||
Some(Box::new(function_type.clone()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_params(
|
||||
function_type: Option<&wasm_functype_t>,
|
||||
) -> Option<&wasm_valtype_vec_t> {
|
||||
let function_type = function_type?;
|
||||
|
||||
Some(function_type.inner().params.as_ref())
|
||||
Some(&function_type.inner().params)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -108,5 +108,5 @@ pub unsafe extern "C" fn wasm_functype_results(
|
||||
) -> Option<&wasm_valtype_vec_t> {
|
||||
let function_type = function_type?;
|
||||
|
||||
Some(function_type.inner().results.as_ref())
|
||||
Some(&function_type.inner().results)
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ use wasmer_api::{ExternType, GlobalType};
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct WasmGlobalType {
|
||||
pub(crate) global_type: GlobalType,
|
||||
content: Box<wasm_valtype_t>,
|
||||
content: wasm_valtype_t,
|
||||
}
|
||||
|
||||
impl WasmGlobalType {
|
||||
pub(crate) fn new(global_type: GlobalType) -> Self {
|
||||
let content = Box::new(global_type.ty.into());
|
||||
let content = global_type.ty.into();
|
||||
|
||||
Self {
|
||||
global_type,
|
||||
@@ -79,5 +79,5 @@ pub unsafe extern "C" fn wasm_globaltype_mutability(
|
||||
pub unsafe extern "C" fn wasm_globaltype_content(
|
||||
global_type: &wasm_globaltype_t,
|
||||
) -> &wasm_valtype_t {
|
||||
global_type.inner().content.as_ref()
|
||||
&global_type.inner().content
|
||||
}
|
||||
|
||||
@@ -1,49 +1,43 @@
|
||||
use super::{owned_wasm_name_t, wasm_externtype_t, wasm_name_t};
|
||||
use super::{wasm_externtype_t, wasm_name_t};
|
||||
use wasmer_api::ImportType;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct wasm_importtype_t {
|
||||
module: owned_wasm_name_t,
|
||||
name: owned_wasm_name_t,
|
||||
extern_type: Box<wasm_externtype_t>,
|
||||
module: wasm_name_t,
|
||||
name: wasm_name_t,
|
||||
extern_type: wasm_externtype_t,
|
||||
}
|
||||
|
||||
wasm_declare_boxed_vec!(importtype);
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_importtype_new(
|
||||
module: Option<&wasm_name_t>,
|
||||
name: Option<&wasm_name_t>,
|
||||
module: Option<Box<wasm_name_t>>,
|
||||
name: Option<Box<wasm_name_t>>,
|
||||
extern_type: Option<Box<wasm_externtype_t>>,
|
||||
) -> Option<Box<wasm_importtype_t>> {
|
||||
let (module, name) = unsafe {
|
||||
(
|
||||
owned_wasm_name_t::new(module?),
|
||||
owned_wasm_name_t::new(name?),
|
||||
)
|
||||
};
|
||||
Some(Box::new(wasm_importtype_t {
|
||||
name,
|
||||
module,
|
||||
extern_type: extern_type?,
|
||||
name: *name?,
|
||||
module: *module?,
|
||||
extern_type: *extern_type?,
|
||||
}))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_importtype_module(import_type: &wasm_importtype_t) -> &wasm_name_t {
|
||||
import_type.module.as_ref()
|
||||
&import_type.module
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_importtype_name(import_type: &wasm_importtype_t) -> &wasm_name_t {
|
||||
import_type.name.as_ref()
|
||||
&import_type.name
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_importtype_type(import_type: &wasm_importtype_t) -> &wasm_externtype_t {
|
||||
import_type.extern_type.as_ref()
|
||||
&import_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -57,9 +51,9 @@ impl From<ImportType> for wasm_importtype_t {
|
||||
|
||||
impl From<&ImportType> for wasm_importtype_t {
|
||||
fn from(other: &ImportType) -> Self {
|
||||
let module: owned_wasm_name_t = other.module().to_string().into();
|
||||
let name: owned_wasm_name_t = other.name().to_string().into();
|
||||
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into());
|
||||
let module: wasm_name_t = other.module().to_string().into();
|
||||
let name: wasm_name_t = other.name().to_string().into();
|
||||
let extern_type: wasm_externtype_t = other.ty().into();
|
||||
|
||||
wasm_importtype_t {
|
||||
module,
|
||||
|
||||
@@ -4,18 +4,18 @@ use wasmer_api::{ExternType, MemoryType, Pages};
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct WasmMemoryType {
|
||||
pub(crate) memory_type: MemoryType,
|
||||
limits: Box<wasm_limits_t>,
|
||||
limits: wasm_limits_t,
|
||||
}
|
||||
|
||||
impl WasmMemoryType {
|
||||
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
||||
let limits = Box::new(wasm_limits_t {
|
||||
let limits = wasm_limits_t {
|
||||
min: memory_type.minimum.0 as _,
|
||||
max: memory_type
|
||||
.maximum
|
||||
.map(|max| max.0 as _)
|
||||
.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||
});
|
||||
};
|
||||
|
||||
Self {
|
||||
memory_type,
|
||||
@@ -79,5 +79,5 @@ const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_limits(memory_type: &wasm_memorytype_t) -> &wasm_limits_t {
|
||||
memory_type.inner().limits.as_ref()
|
||||
&memory_type.inner().limits
|
||||
}
|
||||
|
||||
@@ -28,63 +28,9 @@ wasm_declare_vec!(byte);
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type wasm_name_t = wasm_byte_vec_t;
|
||||
|
||||
impl AsRef<wasm_name_t> for wasm_name_t {
|
||||
fn as_ref(&self) -> &wasm_name_t {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
/// An owned version of `wasm_name_t`.
|
||||
///
|
||||
/// Assumes that data is either valid host-owned or null.
|
||||
// NOTE: `wasm_name_t` already does a deep copy, so we just derive `Clone` here.
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(transparent)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct owned_wasm_name_t(wasm_name_t);
|
||||
|
||||
impl owned_wasm_name_t {
|
||||
/// Take ownership of some `wasm_name_t`
|
||||
///
|
||||
/// # Safety
|
||||
/// You must ensure that the data pointed to by `wasm_name_t` is valid and
|
||||
/// that it is not owned by anyone else.
|
||||
pub unsafe fn new(name: &wasm_name_t) -> Self {
|
||||
Self(wasm_name_t {
|
||||
size: name.size,
|
||||
data: name.data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for owned_wasm_name_t {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.data.is_null() {
|
||||
let _v = unsafe { Vec::from_raw_parts(self.0.data, self.0.size, self.0.size) };
|
||||
self.0.data = std::ptr::null_mut();
|
||||
self.0.size = 0;
|
||||
}
|
||||
// why can't we call this function?
|
||||
//unsafe { crate::wasm_c_api::macros::wasm_byte_vec_delete(Some(self.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<wasm_name_t> for owned_wasm_name_t {
|
||||
fn as_ref(&self) -> &wasm_name_t {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for owned_wasm_name_t {
|
||||
impl From<String> for wasm_name_t {
|
||||
fn from(string: String) -> Self {
|
||||
let mut boxed_str: Box<str> = string.into_boxed_str();
|
||||
let data = boxed_str.as_mut_ptr();
|
||||
let size = boxed_str.bytes().len();
|
||||
let wasm_name = wasm_name_t { data, size };
|
||||
|
||||
Box::leak(boxed_str);
|
||||
|
||||
Self(wasm_name)
|
||||
string.into_bytes().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,21 +10,21 @@ const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct WasmTableType {
|
||||
pub(crate) table_type: TableType,
|
||||
limits: Box<wasm_limits_t>,
|
||||
content: Box<wasm_valtype_t>,
|
||||
pub(crate) _table_type: TableType,
|
||||
limits: wasm_limits_t,
|
||||
content: wasm_valtype_t,
|
||||
}
|
||||
|
||||
impl WasmTableType {
|
||||
pub(crate) fn new(table_type: TableType) -> Self {
|
||||
let limits = Box::new(wasm_limits_t {
|
||||
let limits = wasm_limits_t {
|
||||
min: table_type.minimum as _,
|
||||
max: table_type.maximum.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||
});
|
||||
let content = Box::new(table_type.ty.into());
|
||||
};
|
||||
let content = table_type.ty.into();
|
||||
|
||||
Self {
|
||||
table_type,
|
||||
_table_type: table_type,
|
||||
limits,
|
||||
content,
|
||||
}
|
||||
@@ -79,12 +79,12 @@ pub unsafe extern "C" fn wasm_tabletype_new(
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_limits(table_type: &wasm_tabletype_t) -> &wasm_limits_t {
|
||||
table_type.inner().limits.as_ref()
|
||||
&table_type.inner().limits
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_element(table_type: &wasm_tabletype_t) -> &wasm_valtype_t {
|
||||
table_type.inner().content.as_ref()
|
||||
&table_type.inner().content
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -70,7 +70,7 @@ pub unsafe extern "C" fn wasmer_module_name(
|
||||
}
|
||||
};
|
||||
|
||||
*out = name.as_bytes().to_vec().into();
|
||||
out.set_buffer(name.as_bytes().to_vec());
|
||||
}
|
||||
|
||||
/// Unstable non-standard Wasmer-specific API to set the module's
|
||||
@@ -144,12 +144,9 @@ pub unsafe extern "C" fn wasmer_module_set_name(
|
||||
// own
|
||||
name: &wasm_name_t,
|
||||
) -> bool {
|
||||
let name = match name.into_slice() {
|
||||
Some(name) => match str::from_utf8(name) {
|
||||
let name = match str::from_utf8(name.as_slice()) {
|
||||
Ok(name) => name,
|
||||
Err(_) => return false, // not ideal!
|
||||
},
|
||||
None => return false,
|
||||
};
|
||||
|
||||
match Arc::get_mut(&mut module.inner) {
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
//! ```
|
||||
|
||||
use super::super::types::wasm_name_t;
|
||||
use crate::error::CApiError;
|
||||
use enumset::EnumSet;
|
||||
use std::slice;
|
||||
use std::str::{self, FromStr};
|
||||
@@ -153,7 +152,7 @@ pub unsafe extern "C" fn wasmer_triple_new(
|
||||
)));
|
||||
|
||||
Some(Box::new(wasmer_triple_t {
|
||||
inner: c_try!(Triple::from_str(triple).map_err(|e| CApiError { msg: e.to_string() })),
|
||||
inner: c_try!(Triple::from_str(triple)),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,9 @@
|
||||
//! API.
|
||||
|
||||
use super::super::{
|
||||
externals::wasm_extern_t,
|
||||
module::wasm_module_t,
|
||||
store::wasm_store_t,
|
||||
types::{owned_wasm_name_t, wasm_name_t},
|
||||
externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t,
|
||||
wasi::wasi_env_t,
|
||||
};
|
||||
use crate::error::CApiError;
|
||||
use wasmer_api::Extern;
|
||||
use wasmer_wasi::{generate_import_object_from_env, get_wasi_version};
|
||||
|
||||
@@ -22,8 +18,8 @@ use wasmer_wasi::{generate_import_object_from_env, get_wasi_version};
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_named_extern_t {
|
||||
module: owned_wasm_name_t,
|
||||
name: owned_wasm_name_t,
|
||||
module: wasm_name_t,
|
||||
name: wasm_name_t,
|
||||
r#extern: Box<wasm_extern_t>,
|
||||
}
|
||||
|
||||
@@ -121,7 +117,7 @@ mod __cbindgen_hack__ {
|
||||
pub extern "C" fn wasmer_named_extern_module(
|
||||
named_extern: Option<&wasmer_named_extern_t>,
|
||||
) -> Option<&wasm_name_t> {
|
||||
Some(named_extern?.module.as_ref())
|
||||
Some(&named_extern?.module)
|
||||
}
|
||||
|
||||
/// Non-standard function to get the name of a `wasmer_named_extern_t`.
|
||||
@@ -131,7 +127,7 @@ pub extern "C" fn wasmer_named_extern_module(
|
||||
pub extern "C" fn wasmer_named_extern_name(
|
||||
named_extern: Option<&wasmer_named_extern_t>,
|
||||
) -> Option<&wasm_name_t> {
|
||||
Some(named_extern?.name.as_ref())
|
||||
Some(&named_extern?.name)
|
||||
}
|
||||
|
||||
/// Non-standard function to get the wrapped extern of a
|
||||
@@ -171,29 +167,27 @@ fn wasi_get_unordered_imports_inner(
|
||||
|
||||
let store = &store.inner;
|
||||
|
||||
let version = c_try!(
|
||||
get_wasi_version(&module.inner, false).ok_or_else(|| CApiError {
|
||||
msg: "could not detect a WASI version on the given module".to_string(),
|
||||
})
|
||||
);
|
||||
let version = c_try!(get_wasi_version(&module.inner, false)
|
||||
.ok_or("could not detect a WASI version on the given module"));
|
||||
|
||||
let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);
|
||||
|
||||
*imports = import_object
|
||||
imports.set_buffer(
|
||||
import_object
|
||||
.into_iter()
|
||||
.map(|((module, name), export)| {
|
||||
let module = module.into();
|
||||
let name = name.into();
|
||||
let extern_inner = Extern::from_vm_export(store, export);
|
||||
|
||||
Box::new(wasmer_named_extern_t {
|
||||
Some(Box::new(wasmer_named_extern_t {
|
||||
module,
|
||||
name,
|
||||
r#extern: Box::new(extern_inner.into()),
|
||||
}))
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::types::{wasm_ref_t, wasm_valkind_enum};
|
||||
use crate::error::{update_last_error, CApiError};
|
||||
use crate::error::update_last_error;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use wasmer_api::Val;
|
||||
|
||||
@@ -121,6 +121,15 @@ impl Clone for wasm_val_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for wasm_val_t {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
kind: wasm_valkind_enum::WASM_I64 as _,
|
||||
of: wasm_val_inner { int64_t: 0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_val_copy(
|
||||
// own
|
||||
@@ -147,7 +156,7 @@ pub unsafe extern "C" fn wasm_val_copy(
|
||||
},
|
||||
|
||||
Err(e) => {
|
||||
update_last_error(CApiError { msg: e.to_string() });
|
||||
update_last_error(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use super::{
|
||||
module::wasm_module_t,
|
||||
store::wasm_store_t,
|
||||
};
|
||||
use crate::error::{update_last_error, CApiError};
|
||||
use crate::error::update_last_error;
|
||||
use std::cmp::min;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::CStr;
|
||||
@@ -212,9 +212,7 @@ pub unsafe extern "C" fn wasi_env_read_stdout(
|
||||
if let Some(stdout) = stdout.as_mut() {
|
||||
stdout
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "could not find a file handle for `stdout`".to_string(),
|
||||
});
|
||||
update_last_error("could not find a file handle for `stdout`");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -235,15 +233,11 @@ pub unsafe extern "C" fn wasi_env_read_stderr(
|
||||
if let Some(stderr) = stderr.as_mut() {
|
||||
stderr
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "could not find a file handle for `stderr`".to_string(),
|
||||
});
|
||||
update_last_error("could not find a file handle for `stderr`");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "could not find a file handle for `stderr`".to_string(),
|
||||
});
|
||||
update_last_error("could not find a file handle for `stderr`");
|
||||
return -1;
|
||||
};
|
||||
read_inner(stderr, inner_buffer)
|
||||
@@ -348,33 +342,29 @@ fn wasi_get_imports_inner(
|
||||
|
||||
let store = &store.inner;
|
||||
|
||||
let version = c_try!(
|
||||
get_wasi_version(&module.inner, false).ok_or_else(|| CApiError {
|
||||
msg: "could not detect a WASI version on the given module".to_string(),
|
||||
})
|
||||
);
|
||||
let version = c_try!(get_wasi_version(&module.inner, false)
|
||||
.ok_or("could not detect a WASI version on the given module"));
|
||||
|
||||
let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);
|
||||
|
||||
*imports = module
|
||||
imports.set_buffer(c_try!(module
|
||||
.inner
|
||||
.imports()
|
||||
.map(|import_type| {
|
||||
let export = c_try!(import_object
|
||||
let export = import_object
|
||||
.resolve_by_name(import_type.module(), import_type.name())
|
||||
.ok_or_else(|| CApiError {
|
||||
msg: format!(
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"Failed to resolve import \"{}\" \"{}\"",
|
||||
import_type.module(),
|
||||
import_type.name()
|
||||
),
|
||||
}));
|
||||
)
|
||||
})?;
|
||||
let inner = Extern::from_vm_export(store, export);
|
||||
|
||||
Some(Box::new(inner.into()))
|
||||
Ok(Some(Box::new(inner.into())))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
.into();
|
||||
.collect::<Result<Vec<_>, String>>()));
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
@@ -11,16 +11,8 @@ use super::types::wasm_byte_vec_t;
|
||||
#[cfg(feature = "wat")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t, out: &mut wasm_byte_vec_t) {
|
||||
let wat: &[u8] = match wat.into_slice() {
|
||||
Some(v) => v,
|
||||
_ => {
|
||||
out.data = std::ptr::null_mut();
|
||||
out.size = 0;
|
||||
return;
|
||||
}
|
||||
};
|
||||
let result: wasm_byte_vec_t = match wasmer_api::wat2wasm(wat) {
|
||||
Ok(val) => val.into_owned().into(),
|
||||
match wasmer_api::wat2wasm(wat.as_slice()) {
|
||||
Ok(val) => out.set_buffer(val.into_owned()),
|
||||
Err(err) => {
|
||||
crate::error::update_last_error(err);
|
||||
out.data = std::ptr::null_mut();
|
||||
@@ -28,8 +20,6 @@ pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t, out: &mut wasm_byte_vec
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
*out = result;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -25,9 +25,9 @@ more-asserts = "0.2"
|
||||
gimli = { version = "0.25", optional = true }
|
||||
smallvec = "1.6"
|
||||
loupe = "0.1"
|
||||
target-lexicon = { version = "0.12.2", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
target-lexicon = { version = "0.12.2", default-features = false }
|
||||
cranelift-codegen = { version = "0.76", features = ["all-arch"] }
|
||||
lazy_static = "1.4"
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ use gimli::write::{Address, EhFrame, FrameTable};
|
||||
use loupe::MemoryUsage;
|
||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||
use std::sync::Arc;
|
||||
use target_lexicon::{Architecture, OperatingSystem};
|
||||
use wasmer_compiler::CompileError;
|
||||
use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target};
|
||||
use wasmer_compiler::{
|
||||
@@ -29,14 +30,12 @@ use wasmer_compiler::{
|
||||
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
|
||||
SectionIndex,
|
||||
};
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
use wasmer_compiler::{
|
||||
CustomSection, CustomSectionProtection, Relocation, RelocationKind, RelocationTarget,
|
||||
SectionBody,
|
||||
};
|
||||
use wasmer_types::entity::{EntityRef, PrimaryMap};
|
||||
use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex};
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
use wasmer_vm::libcalls::LibCall;
|
||||
|
||||
/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR,
|
||||
@@ -92,14 +91,13 @@ impl Compiler for CraneliftCompiler {
|
||||
// FDEs will cause some issues in Linux.
|
||||
None
|
||||
} else {
|
||||
use std::sync::Mutex;
|
||||
match target.triple().default_calling_convention() {
|
||||
Ok(CallingConvention::SystemV) => {
|
||||
match isa.create_systemv_cie() {
|
||||
Some(cie) => {
|
||||
let mut dwarf_frametable = FrameTable::default();
|
||||
let cie_id = dwarf_frametable.add_cie(cie);
|
||||
Some((Arc::new(Mutex::new(dwarf_frametable)), cie_id))
|
||||
Some((dwarf_frametable, cie_id))
|
||||
}
|
||||
// Even though we are in a SystemV system, Cranelift doesn't support it
|
||||
None => None,
|
||||
@@ -111,7 +109,10 @@ impl Compiler for CraneliftCompiler {
|
||||
|
||||
let mut custom_sections = PrimaryMap::new();
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
let probestack_trampoline_relocation_target = if target.triple().operating_system
|
||||
== OperatingSystem::Linux
|
||||
&& target.triple().architecture == Architecture::X86_64
|
||||
{
|
||||
let probestack_trampoline = CustomSection {
|
||||
protection: CustomSectionProtection::ReadExecute,
|
||||
// We create a jump to an absolute 64bits address
|
||||
@@ -119,7 +120,8 @@ impl Compiler for CraneliftCompiler {
|
||||
// JMP [IP+0] FF 25 00 00 00 00
|
||||
// 64bits ADDR 00 00 00 00 00 00 00 00 preset to 0 until the relocation takes place
|
||||
bytes: SectionBody::new_with_vec(vec![
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
]),
|
||||
relocations: vec![Relocation {
|
||||
kind: RelocationKind::Abs8,
|
||||
@@ -129,12 +131,14 @@ impl Compiler for CraneliftCompiler {
|
||||
addend: 0,
|
||||
}],
|
||||
};
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
custom_sections.push(probestack_trampoline);
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
let probestack_trampoline_relocation_target = SectionIndex::new(custom_sections.len() - 1);
|
||||
|
||||
let functions = function_body_inputs
|
||||
Some(SectionIndex::new(custom_sections.len() - 1))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (functions, fdes): (Vec<CompiledFunction>, Vec<_>) = function_body_inputs
|
||||
.iter()
|
||||
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
|
||||
.par_iter()
|
||||
@@ -170,12 +174,8 @@ impl Compiler for CraneliftCompiler {
|
||||
)?;
|
||||
|
||||
let mut code_buf: Vec<u8> = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new(
|
||||
&module,
|
||||
func_index,
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
probestack_trampoline_relocation_target,
|
||||
);
|
||||
let mut reloc_sink =
|
||||
RelocSink::new(&module, func_index, probestack_trampoline_relocation_target);
|
||||
let mut trap_sink = TrapSink::new();
|
||||
let mut stackmap_sink = binemit::NullStackMapSink {};
|
||||
context
|
||||
@@ -190,31 +190,31 @@ impl Compiler for CraneliftCompiler {
|
||||
CompileError::Codegen(pretty_error(&context.func, Some(&*isa), error))
|
||||
})?;
|
||||
|
||||
let unwind_info = match compiled_function_unwind_info(&*isa, &context)? {
|
||||
let (unwind_info, fde) = match compiled_function_unwind_info(&*isa, &context)? {
|
||||
#[cfg(feature = "unwind")]
|
||||
CraneliftUnwindInfo::FDE(fde) => {
|
||||
if let Some((dwarf_frametable, cie_id)) = &dwarf_frametable {
|
||||
dwarf_frametable
|
||||
.lock()
|
||||
.expect("Can't write into DWARF frametable")
|
||||
.add_fde(
|
||||
*cie_id,
|
||||
fde.to_fde(Address::Symbol {
|
||||
if dwarf_frametable.is_some() {
|
||||
let fde = fde.to_fde(Address::Symbol {
|
||||
// The symbol is the kind of relocation.
|
||||
// "0" is used for functions
|
||||
symbol: WriterRelocate::FUNCTION_SYMBOL,
|
||||
// We use the addend as a way to specify the
|
||||
// function index
|
||||
addend: i.index() as _,
|
||||
}),
|
||||
);
|
||||
});
|
||||
// The unwind information is inserted into the dwarf section
|
||||
Some(CompiledFunctionUnwindInfo::Dwarf)
|
||||
(Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde))
|
||||
} else {
|
||||
None
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
other => other.maybe_into_to_windows_unwind(),
|
||||
#[cfg(feature = "unwind")]
|
||||
other => (other.maybe_into_to_windows_unwind(), None),
|
||||
|
||||
// This is a bit hacky, but necessary since gimli is not
|
||||
// available when the "unwind" feature is disabled.
|
||||
#[cfg(not(feature = "unwind"))]
|
||||
other => (other.maybe_into_to_windows_unwind(), None::<()>),
|
||||
};
|
||||
|
||||
let range = reader.range();
|
||||
@@ -223,7 +223,8 @@ impl Compiler for CraneliftCompiler {
|
||||
// We transform the Cranelift JumpTable's into compiler JumpTables
|
||||
let func_jt_offsets = transform_jump_table(context.func.jt_offsets);
|
||||
|
||||
Ok(CompiledFunction {
|
||||
Ok((
|
||||
CompiledFunction {
|
||||
body: FunctionBody {
|
||||
body: code_buf,
|
||||
unwind_info,
|
||||
@@ -234,21 +235,23 @@ impl Compiler for CraneliftCompiler {
|
||||
address_map,
|
||||
traps: trap_sink.traps,
|
||||
},
|
||||
})
|
||||
},
|
||||
fde,
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<_>, CompileError>>()?
|
||||
.into_iter()
|
||||
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
|
||||
.unzip();
|
||||
|
||||
#[cfg(feature = "unwind")]
|
||||
let dwarf = {
|
||||
let dwarf = if let Some((dwarf_frametable, _cie_id)) = dwarf_frametable {
|
||||
let dwarf = if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable {
|
||||
for fde in fdes {
|
||||
if let Some(fde) = fde {
|
||||
dwarf_frametable.add_fde(cie_id, fde);
|
||||
}
|
||||
}
|
||||
let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok()));
|
||||
dwarf_frametable
|
||||
.lock()
|
||||
.unwrap()
|
||||
.write_eh_frame(&mut eh_frame)
|
||||
.unwrap();
|
||||
dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap();
|
||||
|
||||
let eh_frame_section = eh_frame.0.into_section();
|
||||
custom_sections.push(eh_frame_section);
|
||||
@@ -256,8 +259,6 @@ impl Compiler for CraneliftCompiler {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
dwarf
|
||||
};
|
||||
#[cfg(not(feature = "unwind"))]
|
||||
let dwarf = None;
|
||||
|
||||
@@ -289,7 +290,7 @@ impl Compiler for CraneliftCompiler {
|
||||
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>();
|
||||
|
||||
Ok(Compilation::new(
|
||||
functions,
|
||||
functions.into_iter().collect(),
|
||||
custom_sections,
|
||||
function_call_trampolines,
|
||||
dynamic_function_trampolines,
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
|
||||
use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind};
|
||||
use cranelift_codegen::binemit;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use cranelift_codegen::ir::LibCall;
|
||||
use cranelift_codegen::ir::{self, ExternalName};
|
||||
use cranelift_entity::EntityRef as CraneliftEntityRef;
|
||||
use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation};
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
use wasmer_compiler::{RelocationKind, SectionIndex};
|
||||
use wasmer_types::entity::EntityRef;
|
||||
use wasmer_types::{FunctionIndex, LocalFunctionIndex, ModuleInfo};
|
||||
@@ -24,8 +22,7 @@ pub(crate) struct RelocSink<'a> {
|
||||
pub func_relocs: Vec<Relocation>,
|
||||
|
||||
/// The section where the probestack trampoline call is located
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
pub probestack_trampoline_relocation_target: SectionIndex,
|
||||
pub probestack_trampoline_relocation_target: Option<SectionIndex>,
|
||||
}
|
||||
|
||||
impl<'a> binemit::RelocSink for RelocSink<'a> {
|
||||
@@ -45,13 +42,12 @@ impl<'a> binemit::RelocSink for RelocSink<'a> {
|
||||
.expect("The provided function should be local"),
|
||||
)
|
||||
} else if let ExternalName::LibCall(libcall) = *name {
|
||||
match libcall {
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
LibCall::Probestack => {
|
||||
match (libcall, self.probestack_trampoline_relocation_target) {
|
||||
(LibCall::Probestack, Some(probestack_trampoline_relocation_target)) => {
|
||||
self.func_relocs.push(Relocation {
|
||||
kind: RelocationKind::X86CallPCRel4,
|
||||
reloc_target: RelocationTarget::CustomSection(
|
||||
self.probestack_trampoline_relocation_target,
|
||||
probestack_trampoline_relocation_target,
|
||||
),
|
||||
offset: offset,
|
||||
addend: addend,
|
||||
@@ -100,8 +96,7 @@ impl<'a> RelocSink<'a> {
|
||||
pub fn new(
|
||||
module: &'a ModuleInfo,
|
||||
func_index: FunctionIndex,
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
probestack_trampoline_relocation_target: SectionIndex,
|
||||
probestack_trampoline_relocation_target: Option<SectionIndex>,
|
||||
) -> Self {
|
||||
let local_func_index = module
|
||||
.local_func_index(func_index)
|
||||
@@ -110,7 +105,6 @@ impl<'a> RelocSink<'a> {
|
||||
module,
|
||||
local_func_index,
|
||||
func_relocs: Vec::new(),
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
probestack_trampoline_relocation_target,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ loupe = "0.1"
|
||||
package = "inkwell"
|
||||
version = "0.1.0-beta.4"
|
||||
default-features = false
|
||||
features = ["llvm11-0", "target-x86", "target-aarch64"]
|
||||
features = ["llvm12-0", "target-x86", "target-aarch64"]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
@@ -24,14 +24,14 @@ to native speeds.
|
||||
## Requirements
|
||||
|
||||
The LLVM compiler requires a valid installation of LLVM in your system.
|
||||
It currently requires **LLVM 11**.
|
||||
It currently requires **LLVM 12**.
|
||||
|
||||
|
||||
You can install LLVM easily on your Debian-like system via this command:
|
||||
|
||||
```bash
|
||||
wget https://apt.llvm.org/llvm.sh -O /tmp/llvm.sh
|
||||
sudo bash /tmp/llvm.sh 11
|
||||
sudo bash /tmp/llvm.sh 12
|
||||
```
|
||||
|
||||
Or in macOS:
|
||||
|
||||
@@ -4,7 +4,7 @@ use inkwell::{
|
||||
attributes::{Attribute, AttributeLoc},
|
||||
builder::Builder,
|
||||
context::Context,
|
||||
types::{BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
|
||||
types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
|
||||
values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue},
|
||||
AddressSpace,
|
||||
};
|
||||
@@ -206,17 +206,16 @@ impl Abi for Aarch64SystemV {
|
||||
.map(|&ty| type_to_llvm(intrinsics, ty))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let sret = context
|
||||
.struct_type(&basic_types, false)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
let sret = context.struct_type(&basic_types, false);
|
||||
let sret_ptr = sret.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let param_types =
|
||||
std::iter::once(Ok(sret.as_basic_type_enum())).chain(param_types);
|
||||
std::iter::once(Ok(sret_ptr.as_basic_type_enum())).chain(param_types);
|
||||
|
||||
let mut attributes = vec![(
|
||||
context.create_enum_attribute(
|
||||
context.create_type_attribute(
|
||||
Attribute::get_named_enum_kind_id("sret"),
|
||||
0,
|
||||
sret.as_any_type_enum(),
|
||||
),
|
||||
AttributeLoc::Param(0),
|
||||
)];
|
||||
|
||||
@@ -4,7 +4,7 @@ use inkwell::{
|
||||
attributes::{Attribute, AttributeLoc},
|
||||
builder::Builder,
|
||||
context::Context,
|
||||
types::{BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
|
||||
types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
|
||||
values::{
|
||||
BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue,
|
||||
PointerValue, VectorValue,
|
||||
@@ -263,14 +263,17 @@ impl Abi for X86_64SystemV {
|
||||
.map(|&ty| type_to_llvm(intrinsics, ty))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let sret = context
|
||||
.struct_type(&basic_types, false)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
let sret = context.struct_type(&basic_types, false);
|
||||
let sret_ptr = sret.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let param_types = std::iter::once(Ok(sret.as_basic_type_enum())).chain(param_types);
|
||||
let param_types =
|
||||
std::iter::once(Ok(sret_ptr.as_basic_type_enum())).chain(param_types);
|
||||
|
||||
let mut attributes = vec![(
|
||||
context.create_enum_attribute(Attribute::get_named_enum_kind_id("sret"), 0),
|
||||
context.create_type_attribute(
|
||||
Attribute::get_named_enum_kind_id("sret"),
|
||||
sret.as_any_type_enum(),
|
||||
),
|
||||
AttributeLoc::Param(0),
|
||||
)];
|
||||
attributes.append(&mut vmctx_attributes(1));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::address_map::get_function_address_map;
|
||||
use crate::{common_decl::*, config::Singlepass, emitter_x64::*, machine::Machine, x64_decl::*};
|
||||
use dynasmrt::{x64::Assembler, DynamicLabel};
|
||||
use dynasmrt::{x64::X64Relocation, DynamicLabel, VecAssembler};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::collections::BTreeMap;
|
||||
use std::iter;
|
||||
@@ -22,6 +22,8 @@ use wasmer_types::{
|
||||
};
|
||||
use wasmer_vm::{MemoryStyle, TableStyle, TrapCode, VMBuiltinFunctionIndex, VMOffsets};
|
||||
|
||||
type Assembler = VecAssembler<X64Relocation>;
|
||||
|
||||
/// The singlepass per-function code generator.
|
||||
pub struct FuncGen<'a> {
|
||||
// Immutable properties assigned at creation time.
|
||||
@@ -89,6 +91,9 @@ pub struct FuncGen<'a> {
|
||||
///
|
||||
// Ordered by increasing InstructionAddressMap::srcloc.
|
||||
instructions_address_map: Vec<InstructionAddressMap>,
|
||||
|
||||
/// Calling convention to use.
|
||||
calling_convention: CallingConvention,
|
||||
}
|
||||
|
||||
struct SpecialLabelSet {
|
||||
@@ -1010,7 +1015,7 @@ impl<'a> FuncGen<'a> {
|
||||
self.machine.state.stack_values.push(content);
|
||||
}
|
||||
}
|
||||
let calling_convention = self.config.calling_convention;
|
||||
let calling_convention = self.calling_convention;
|
||||
|
||||
let stack_padding: usize = match calling_convention {
|
||||
CallingConvention::WindowsFastcall => 32,
|
||||
@@ -1756,7 +1761,7 @@ impl<'a> FuncGen<'a> {
|
||||
&mut self.assembler,
|
||||
self.local_types.len(),
|
||||
self.signature.params().len(),
|
||||
self.config.calling_convention,
|
||||
self.calling_convention,
|
||||
);
|
||||
|
||||
// Mark vmctx register. The actual loading of the vmctx value is handled by init_local.
|
||||
@@ -1823,6 +1828,7 @@ impl<'a> FuncGen<'a> {
|
||||
_table_styles: &'a PrimaryMap<TableIndex, TableStyle>,
|
||||
local_func_index: LocalFunctionIndex,
|
||||
local_types_excluding_arguments: &[WpType],
|
||||
calling_convention: CallingConvention,
|
||||
) -> Result<FuncGen<'a>, CodegenError> {
|
||||
let func_index = module.func_index(local_func_index);
|
||||
let sig_index = module.functions[func_index];
|
||||
@@ -1844,7 +1850,7 @@ impl<'a> FuncGen<'a> {
|
||||
.collect(),
|
||||
);
|
||||
|
||||
let mut assembler = Assembler::new().unwrap();
|
||||
let mut assembler = Assembler::new(0);
|
||||
let special_labels = SpecialLabelSet {
|
||||
integer_division_by_zero: assembler.get_label(),
|
||||
heap_access_oob: assembler.get_label(),
|
||||
@@ -1874,6 +1880,7 @@ impl<'a> FuncGen<'a> {
|
||||
special_labels,
|
||||
src_loc: 0,
|
||||
instructions_address_map: vec![],
|
||||
calling_convention,
|
||||
};
|
||||
fg.emit_head()?;
|
||||
Ok(fg)
|
||||
@@ -5404,7 +5411,7 @@ impl<'a> FuncGen<'a> {
|
||||
self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize;
|
||||
let vmcaller_checked_anyfunc_vmctx =
|
||||
self.vmoffsets.vmcaller_checked_anyfunc_vmctx() as usize;
|
||||
let calling_convention = self.config.calling_convention;
|
||||
let calling_convention = self.calling_convention;
|
||||
|
||||
self.emit_call_native(
|
||||
|this| {
|
||||
@@ -6698,7 +6705,7 @@ impl<'a> FuncGen<'a> {
|
||||
self.machine.finalize_locals(
|
||||
&mut self.assembler,
|
||||
&self.locals,
|
||||
self.config.calling_convention,
|
||||
self.calling_convention,
|
||||
);
|
||||
self.assembler.emit_mov(
|
||||
Size::S64,
|
||||
@@ -8811,7 +8818,7 @@ pub fn gen_std_trampoline(
|
||||
sig: &FunctionType,
|
||||
calling_convention: CallingConvention,
|
||||
) -> FunctionBody {
|
||||
let mut a = Assembler::new().unwrap();
|
||||
let mut a = Assembler::new(0);
|
||||
|
||||
// Calculate stack offset.
|
||||
let mut stack_offset: u32 = 0;
|
||||
@@ -8921,7 +8928,7 @@ pub fn gen_std_dynamic_import_trampoline(
|
||||
sig: &FunctionType,
|
||||
calling_convention: CallingConvention,
|
||||
) -> FunctionBody {
|
||||
let mut a = Assembler::new().unwrap();
|
||||
let mut a = Assembler::new(0);
|
||||
|
||||
// Allocate argument array.
|
||||
let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len()) + 8; // 16 bytes each + 8 bytes sysv call padding
|
||||
@@ -9043,7 +9050,7 @@ pub fn gen_import_call_trampoline(
|
||||
sig: &FunctionType,
|
||||
calling_convention: CallingConvention,
|
||||
) -> CustomSection {
|
||||
let mut a = Assembler::new().unwrap();
|
||||
let mut a = Assembler::new(0);
|
||||
|
||||
// TODO: ARM entry trampoline is not emitted.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::{
|
||||
Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo,
|
||||
CompiledFunction, Compiler, CompilerConfig, FunctionBinaryReader, FunctionBody,
|
||||
CompiledFunction, Compiler, CompilerConfig, CpuFeature, FunctionBinaryReader, FunctionBody,
|
||||
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
|
||||
ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation,
|
||||
};
|
||||
@@ -62,8 +62,15 @@ impl Compiler for SinglepassCompiler {
|
||||
OperatingSystem::Windows.to_string(),
|
||||
));
|
||||
}*/
|
||||
if let Architecture::X86_32(arch) = target.triple().architecture {
|
||||
return Err(CompileError::UnsupportedTarget(arch.to_string()));
|
||||
if target.triple().architecture != Architecture::X86_64 {
|
||||
return Err(CompileError::UnsupportedTarget(
|
||||
target.triple().architecture.to_string(),
|
||||
));
|
||||
}
|
||||
if !target.cpu_features().contains(CpuFeature::AVX) {
|
||||
return Err(CompileError::UnsupportedTarget(
|
||||
"x86_64 without AVX".to_string(),
|
||||
));
|
||||
}
|
||||
if compile_info.features.multi_value {
|
||||
return Err(CompileError::UnsupportedFeature("multivalue".to_string()));
|
||||
@@ -125,6 +132,7 @@ impl Compiler for SinglepassCompiler {
|
||||
&table_styles,
|
||||
i,
|
||||
&locals,
|
||||
calling_convention,
|
||||
)
|
||||
.map_err(to_compile_error)?;
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
use crate::compiler::SinglepassCompiler;
|
||||
use loupe::MemoryUsage;
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::{
|
||||
CallingConvention, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target,
|
||||
};
|
||||
use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target};
|
||||
use wasmer_types::Features;
|
||||
|
||||
#[derive(Debug, Clone, MemoryUsage)]
|
||||
@@ -15,8 +13,6 @@ pub struct Singlepass {
|
||||
pub(crate) enable_stack_check: bool,
|
||||
/// The middleware chain.
|
||||
pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
|
||||
#[loupe(skip)]
|
||||
pub(crate) calling_convention: CallingConvention,
|
||||
}
|
||||
|
||||
impl Singlepass {
|
||||
@@ -27,12 +23,6 @@ impl Singlepass {
|
||||
enable_nan_canonicalization: true,
|
||||
enable_stack_check: false,
|
||||
middlewares: vec![],
|
||||
calling_convention: match Target::default().triple().default_calling_convention() {
|
||||
Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall,
|
||||
Ok(CallingConvention::SystemV) => CallingConvention::SystemV,
|
||||
//Ok(CallingConvention::AppleAarch64) => AppleAarch64,
|
||||
_ => panic!("Unsupported Calling convention for Singlepass"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
pub use crate::x64_decl::{GPR, XMM};
|
||||
use dynasm::dynasm;
|
||||
use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi};
|
||||
use dynasmrt::{
|
||||
x64::X64Relocation, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, VecAssembler,
|
||||
};
|
||||
|
||||
type Assembler = VecAssembler<X64Relocation>;
|
||||
|
||||
/// Force `dynasm!` to use the correct arch (x64) when cross-compiling.
|
||||
/// `dynasm!` proc-macro tries to auto-detect it by default by looking at the
|
||||
@@ -479,7 +483,7 @@ macro_rules! binop_shift {
|
||||
|
||||
macro_rules! jmp_op {
|
||||
($ins:ident, $assembler:tt, $label:ident) => {
|
||||
dynasm!($assembler ; $ins =>$label);
|
||||
dynasm!($assembler ; $ins =>$label)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -586,12 +586,14 @@ impl Machine {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use dynasmrt::x64::Assembler;
|
||||
use dynasmrt::x64::X64Relocation;
|
||||
use dynasmrt::VecAssembler;
|
||||
type Assembler = VecAssembler<X64Relocation>;
|
||||
|
||||
#[test]
|
||||
fn test_release_locations_keep_state_nopanic() {
|
||||
let mut machine = Machine::new();
|
||||
let mut assembler = Assembler::new().unwrap();
|
||||
let mut assembler = Assembler::new(0);
|
||||
let locs = machine.acquire_locations(
|
||||
&mut assembler,
|
||||
&(0..10)
|
||||
|
||||
@@ -21,7 +21,7 @@ serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
thiserror = "1.0"
|
||||
serde_bytes = { version = "0.11", optional = true }
|
||||
smallvec = "1.6"
|
||||
rkyv = { version = "0.6.1", optional = true }
|
||||
rkyv = { version = "0.7.20", optional = true }
|
||||
loupe = "0.1"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -22,7 +22,7 @@ use wasmer_types::entity::entity_impl;
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, MemoryUsage)]
|
||||
pub struct SectionIndex(u32);
|
||||
|
||||
@@ -23,8 +23,9 @@ leb128 = "0.2"
|
||||
libloading = "0.7"
|
||||
tempfile = "3.1"
|
||||
which = "4.0"
|
||||
rkyv = "0.6.1"
|
||||
rkyv = "0.7.20"
|
||||
loupe = "0.1"
|
||||
enumset = "1.0"
|
||||
|
||||
[features]
|
||||
# Enable the `compiler` feature if you want the engine to compile
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::engine::{DylibEngine, DylibEngineInner};
|
||||
use crate::serialize::{ArchivedModuleMetadata, ModuleMetadata};
|
||||
use enumset::EnumSet;
|
||||
use libloading::{Library, Symbol as LibrarySymbol};
|
||||
use loupe::MemoryUsage;
|
||||
use std::error::Error;
|
||||
@@ -17,8 +18,8 @@ use tracing::log::error;
|
||||
#[cfg(feature = "compiler")]
|
||||
use tracing::trace;
|
||||
use wasmer_compiler::{
|
||||
Architecture, CompileError, CompiledFunctionFrameInfo, Features, FunctionAddressMap,
|
||||
OperatingSystem, Symbol, SymbolRegistry, Triple,
|
||||
Architecture, CompileError, CompiledFunctionFrameInfo, CpuFeature, Features,
|
||||
FunctionAddressMap, OperatingSystem, Symbol, SymbolRegistry, Triple,
|
||||
};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{
|
||||
@@ -211,6 +212,7 @@ impl DylibArtifact {
|
||||
prefix: engine_inner.get_prefix(&data),
|
||||
data_initializers,
|
||||
function_body_lengths,
|
||||
cpu_features: target.cpu_features().as_u64(),
|
||||
};
|
||||
|
||||
let serialized_data = metadata.serialize()?;
|
||||
@@ -800,6 +802,10 @@ impl Artifact for DylibArtifact {
|
||||
&self.metadata.compile_info.features
|
||||
}
|
||||
|
||||
fn cpu_features(&self) -> enumset::EnumSet<CpuFeature> {
|
||||
EnumSet::from_u64(self.metadata.cpu_features)
|
||||
}
|
||||
|
||||
fn data_initializers(&self) -> &[OwnedDataInitializer] {
|
||||
&*self.metadata.data_initializers
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use loupe::MemoryUsage;
|
||||
use rkyv::{
|
||||
archived_value,
|
||||
de::{adapters::SharedDeserializerAdapter, deserializers::AllocDeserializer},
|
||||
ser::adapters::SharedSerializerAdapter,
|
||||
ser::{serializers::WriteSerializer, Serializer as RkyvSerializer},
|
||||
Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize,
|
||||
archived_value, de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer,
|
||||
ser::Serializer as RkyvSerializer, Archive, Deserialize as RkyvDeserialize,
|
||||
Serialize as RkyvSerialize,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
@@ -35,6 +33,7 @@ pub struct ModuleMetadata {
|
||||
pub data_initializers: Box<[OwnedDataInitializer]>,
|
||||
// The function body lengths (used to find function by address)
|
||||
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
|
||||
pub cpu_features: u64,
|
||||
}
|
||||
|
||||
pub struct ModuleMetadataSymbolRegistry<'a> {
|
||||
@@ -59,11 +58,11 @@ impl ModuleMetadata {
|
||||
}
|
||||
|
||||
pub fn serialize(&mut self) -> Result<Vec<u8>, CompileError> {
|
||||
let mut serializer = SharedSerializerAdapter::new(WriteSerializer::new(vec![]));
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
let pos = serializer.serialize_value(self).map_err(to_compile_error)? as u64;
|
||||
let mut serialized_data = serializer.into_inner().into_inner();
|
||||
let mut serialized_data = serializer.into_serializer().into_inner();
|
||||
serialized_data.extend_from_slice(&pos.to_le_bytes());
|
||||
Ok(serialized_data)
|
||||
Ok(serialized_data.to_vec())
|
||||
}
|
||||
|
||||
pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
|
||||
@@ -86,7 +85,7 @@ impl ModuleMetadata {
|
||||
pub fn deserialize_from_archive(
|
||||
archived: &ArchivedModuleMetadata,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let mut deserializer = SharedDeserializerAdapter::new(AllocDeserializer);
|
||||
let mut deserializer = SharedDeserializeMap::new();
|
||||
RkyvDeserialize::deserialize(archived, &mut deserializer)
|
||||
.map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ leb128 = "0.2"
|
||||
libloading = "0.7"
|
||||
tempfile = "3.1"
|
||||
loupe = "0.1"
|
||||
enumset = "1.0"
|
||||
|
||||
[features]
|
||||
# Enable the `compiler` feature if you want the engine to compile
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
|
||||
use crate::engine::{StaticlibEngine, StaticlibEngineInner};
|
||||
use crate::serialize::{ModuleMetadata, ModuleMetadataSymbolRegistry};
|
||||
use enumset::EnumSet;
|
||||
use loupe::MemoryUsage;
|
||||
use std::collections::BTreeMap;
|
||||
use std::error::Error;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::{CompileError, Features, OperatingSystem, SymbolRegistry, Triple};
|
||||
use wasmer_compiler::{
|
||||
CompileError, CpuFeature, Features, OperatingSystem, SymbolRegistry, Triple,
|
||||
};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{
|
||||
CompileModuleInfo, Compiler, FunctionBodyData, ModuleEnvironment, ModuleMiddlewareChain,
|
||||
@@ -46,6 +49,7 @@ pub struct StaticlibArtifact {
|
||||
/// Length of the serialized metadata
|
||||
metadata_length: usize,
|
||||
symbol_registry: ModuleMetadataSymbolRegistry,
|
||||
is_compiled: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -181,6 +185,7 @@ impl StaticlibArtifact {
|
||||
prefix: engine_inner.get_prefix(&data),
|
||||
data_initializers,
|
||||
function_body_lengths,
|
||||
cpu_features: target.cpu_features().as_u64(),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -295,6 +300,7 @@ impl StaticlibArtifact {
|
||||
func_data_registry: engine_inner.func_data().clone(),
|
||||
metadata_length,
|
||||
symbol_registry,
|
||||
is_compiled: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -415,6 +421,7 @@ impl StaticlibArtifact {
|
||||
func_data_registry,
|
||||
metadata_length: 0,
|
||||
symbol_registry,
|
||||
is_compiled: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -450,6 +457,10 @@ impl Artifact for StaticlibArtifact {
|
||||
&self.metadata.compile_info.features
|
||||
}
|
||||
|
||||
fn cpu_features(&self) -> EnumSet<CpuFeature> {
|
||||
EnumSet::from_u64(self.metadata.cpu_features)
|
||||
}
|
||||
|
||||
fn data_initializers(&self) -> &[OwnedDataInitializer] {
|
||||
&*self.metadata.data_initializers
|
||||
}
|
||||
@@ -483,6 +494,12 @@ impl Artifact for StaticlibArtifact {
|
||||
}
|
||||
|
||||
fn preinstantiate(&self) -> Result<(), InstantiationError> {
|
||||
if self.is_compiled {
|
||||
panic!(
|
||||
"a module built with the staticlib engine must be linked \
|
||||
into the current executable"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ pub struct ModuleMetadata {
|
||||
pub data_initializers: Box<[OwnedDataInitializer]>,
|
||||
// The function body lengths (used to find function by address)
|
||||
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
|
||||
pub cpu_features: u64,
|
||||
}
|
||||
|
||||
#[derive(MemoryUsage)]
|
||||
|
||||
@@ -11,16 +11,22 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-types = { path = "../types", version = "2.0.0", features = ["enable-rkyv"] }
|
||||
wasmer-compiler = { path = "../compiler", version = "2.0.0", features = ["translator", "enable-rkyv"] }
|
||||
wasmer-types = { path = "../types", version = "2.0.0", features = [
|
||||
"enable-rkyv",
|
||||
] }
|
||||
wasmer-compiler = { path = "../compiler", version = "2.0.0", features = [
|
||||
"translator",
|
||||
"enable-rkyv",
|
||||
] }
|
||||
wasmer-vm = { path = "../vm", version = "2.0.0", features = ["enable-rkyv"] }
|
||||
wasmer-engine = { path = "../engine", version = "2.0.0" }
|
||||
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
||||
region = "3.0"
|
||||
cfg-if = "1.0"
|
||||
leb128 = "0.2"
|
||||
rkyv = "0.6.1"
|
||||
rkyv = "0.7.20"
|
||||
loupe = "0.1"
|
||||
enumset = "1.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3", features = ["winnt", "impl-default"] }
|
||||
|
||||
@@ -6,9 +6,10 @@ use crate::link::link_module;
|
||||
#[cfg(feature = "compiler")]
|
||||
use crate::serialize::SerializableCompilation;
|
||||
use crate::serialize::SerializableModule;
|
||||
use enumset::EnumSet;
|
||||
use loupe::MemoryUsage;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use wasmer_compiler::{CompileError, Features, Triple};
|
||||
use wasmer_compiler::{CompileError, CpuFeature, Features, Triple};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment, ModuleMiddlewareChain};
|
||||
use wasmer_engine::{
|
||||
@@ -128,6 +129,7 @@ impl UniversalArtifact {
|
||||
compilation: serializable_compilation,
|
||||
compile_info,
|
||||
data_initializers,
|
||||
cpu_features: engine.target().cpu_features().as_u64(),
|
||||
};
|
||||
Self::from_parts(&mut inner_engine, serializable)
|
||||
}
|
||||
@@ -307,6 +309,10 @@ impl Artifact for UniversalArtifact {
|
||||
&self.serializable.compile_info.features
|
||||
}
|
||||
|
||||
fn cpu_features(&self) -> EnumSet<CpuFeature> {
|
||||
EnumSet::from_u64(self.serializable.cpu_features)
|
||||
}
|
||||
|
||||
fn data_initializers(&self) -> &[OwnedDataInitializer] {
|
||||
&*self.serializable.data_initializers
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use loupe::MemoryUsage;
|
||||
use rkyv::{
|
||||
archived_value,
|
||||
de::{adapters::SharedDeserializerAdapter, deserializers::AllocDeserializer},
|
||||
ser::adapters::SharedSerializerAdapter,
|
||||
ser::{serializers::WriteSerializer, Serializer as RkyvSerializer},
|
||||
Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize,
|
||||
archived_value, de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer,
|
||||
ser::Serializer as RkyvSerializer, Archive, Deserialize as RkyvDeserialize,
|
||||
Serialize as RkyvSerialize,
|
||||
};
|
||||
use wasmer_compiler::{
|
||||
CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody,
|
||||
@@ -38,6 +36,7 @@ pub struct SerializableModule {
|
||||
pub compilation: SerializableCompilation,
|
||||
pub compile_info: CompileModuleInfo,
|
||||
pub data_initializers: Box<[OwnedDataInitializer]>,
|
||||
pub cpu_features: u64,
|
||||
}
|
||||
|
||||
fn to_serialize_error(err: impl std::error::Error) -> SerializeError {
|
||||
@@ -49,13 +48,13 @@ impl SerializableModule {
|
||||
/// The bytes will have the following format:
|
||||
/// RKYV serialization (any length) + POS (8 bytes)
|
||||
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
let mut serializer = SharedSerializerAdapter::new(WriteSerializer::new(vec![]));
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
let pos = serializer
|
||||
.serialize_value(self)
|
||||
.map_err(to_serialize_error)? as u64;
|
||||
let mut serialized_data = serializer.into_inner().into_inner();
|
||||
let mut serialized_data = serializer.into_serializer().into_inner();
|
||||
serialized_data.extend_from_slice(&pos.to_le_bytes());
|
||||
Ok(serialized_data)
|
||||
Ok(serialized_data.to_vec())
|
||||
}
|
||||
|
||||
/// Deserialize a Module from a slice.
|
||||
@@ -98,7 +97,7 @@ impl SerializableModule {
|
||||
pub fn deserialize_from_archive(
|
||||
archived: &ArchivedSerializableModule,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let mut deserializer = SharedDeserializerAdapter::new(AllocDeserializer);
|
||||
let mut deserializer = SharedDeserializeMap::new();
|
||||
RkyvDeserialize::deserialize(archived, &mut deserializer)
|
||||
.map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_bytes = { version = "0.11" }
|
||||
lazy_static = "1.4"
|
||||
loupe = "0.1"
|
||||
enumset = "1.0"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use crate::{
|
||||
resolve_imports, InstantiationError, Resolver, RuntimeError, SerializeError, Tunables,
|
||||
};
|
||||
use enumset::EnumSet;
|
||||
use loupe::MemoryUsage;
|
||||
use std::any::Any;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::Features;
|
||||
use wasmer_compiler::{CpuFeature, Features};
|
||||
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
|
||||
use wasmer_types::{
|
||||
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo,
|
||||
@@ -43,6 +44,9 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
|
||||
/// Returns the features for this Artifact
|
||||
fn features(&self) -> &Features;
|
||||
|
||||
/// Returns the CPU features for this Artifact
|
||||
fn cpu_features(&self) -> EnumSet<CpuFeature>;
|
||||
|
||||
/// Returns the memory styles associated with this `Artifact`.
|
||||
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>;
|
||||
|
||||
@@ -96,6 +100,16 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
|
||||
resolver: &dyn Resolver,
|
||||
host_state: Box<dyn Any>,
|
||||
) -> Result<InstanceHandle, InstantiationError> {
|
||||
// Validate the CPU features this module was compiled with against the
|
||||
// host CPU features.
|
||||
let host_cpu_features = CpuFeature::for_host();
|
||||
if !host_cpu_features.is_superset(self.cpu_features()) {
|
||||
Err(InstantiationError::CpuFeature(format!(
|
||||
"{:?}",
|
||||
self.cpu_features().difference(host_cpu_features)
|
||||
)))?;
|
||||
}
|
||||
|
||||
self.preinstantiate()?;
|
||||
|
||||
let module = self.module();
|
||||
|
||||
@@ -91,6 +91,11 @@ pub enum InstantiationError {
|
||||
#[error(transparent)]
|
||||
Link(LinkError),
|
||||
|
||||
/// The module was compiled with a CPU feature that is not available on
|
||||
/// the current host.
|
||||
#[error("module compiled with CPU feature that is missing from host")]
|
||||
CpuFeature(String),
|
||||
|
||||
/// A runtime error occured while invoking the start function
|
||||
#[error(transparent)]
|
||||
Start(RuntimeError),
|
||||
|
||||
@@ -14,7 +14,7 @@ edition = "2018"
|
||||
serde = { version = "1.0", features = ["derive", "rc"], optional = true, default-features = false }
|
||||
thiserror = "1.0"
|
||||
indexmap = { version = "1.6", features = ["serde-1"] }
|
||||
rkyv = { version = "0.6.1", optional = true }
|
||||
rkyv = { version = "0.7.20", optional = true }
|
||||
loupe = { version = "0.1", features = ["enable-indexmap"] }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -3,32 +3,31 @@ use core::hash::Hash;
|
||||
use indexmap::IndexMap;
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
#[cfg(feature = "std")]
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Serialize, Deserialize, Archive)]
|
||||
/// Rkyv Archivable IndexMap
|
||||
pub struct ArchivableIndexMap<K: Hash + Eq + Archive, V: Archive> {
|
||||
indices: HashMap<K, u64>,
|
||||
pub struct ArchivableIndexMap<K: Hash + Ord + Archive, V: Archive> {
|
||||
entries: Vec<(K, V)>,
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Archive + Clone, V: Archive> From<IndexMap<K, V>> for ArchivableIndexMap<K, V> {
|
||||
impl<K: Hash + Ord + Archive + Clone, V: Archive> From<IndexMap<K, V>>
|
||||
for ArchivableIndexMap<K, V>
|
||||
{
|
||||
fn from(it: IndexMap<K, V>) -> ArchivableIndexMap<K, V> {
|
||||
let mut r = ArchivableIndexMap {
|
||||
indices: HashMap::new(),
|
||||
entries: Vec::new(),
|
||||
};
|
||||
let mut i: u64 = 0;
|
||||
for (k, v) in it.into_iter() {
|
||||
r.indices.insert(k.clone(), i);
|
||||
r.entries.push((k, v));
|
||||
i += 1;
|
||||
}
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Archive + Clone, V: Archive> Into<IndexMap<K, V>> for ArchivableIndexMap<K, V> {
|
||||
impl<K: Hash + Ord + Archive + Clone, V: Archive> Into<IndexMap<K, V>>
|
||||
for ArchivableIndexMap<K, V>
|
||||
{
|
||||
fn into(self) -> IndexMap<K, V> {
|
||||
let mut r = IndexMap::new();
|
||||
for (k, v) in self.entries.into_iter() {
|
||||
|
||||
@@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct LocalFunctionIndex(u32);
|
||||
entity_impl!(LocalFunctionIndex);
|
||||
@@ -44,7 +44,7 @@ entity_impl!(LocalMemoryIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct LocalGlobalIndex(u32);
|
||||
entity_impl!(LocalGlobalIndex);
|
||||
@@ -60,7 +60,7 @@ entity_impl!(ArchivedLocalGlobalIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct FunctionIndex(u32);
|
||||
entity_impl!(FunctionIndex);
|
||||
@@ -76,7 +76,7 @@ entity_impl!(ArchivedFunctionIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct TableIndex(u32);
|
||||
entity_impl!(TableIndex);
|
||||
@@ -92,7 +92,7 @@ entity_impl!(ArchivedTableIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct GlobalIndex(u32);
|
||||
entity_impl!(GlobalIndex);
|
||||
@@ -108,7 +108,7 @@ entity_impl!(ArchivedGlobalIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct MemoryIndex(u32);
|
||||
entity_impl!(MemoryIndex);
|
||||
@@ -124,7 +124,7 @@ entity_impl!(ArchivedMemoryIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct SignatureIndex(u32);
|
||||
entity_impl!(SignatureIndex);
|
||||
@@ -140,7 +140,7 @@ entity_impl!(ArchivedSignatureIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct DataIndex(u32);
|
||||
entity_impl!(DataIndex);
|
||||
@@ -156,7 +156,7 @@ entity_impl!(ArchivedDataIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct ElemIndex(u32);
|
||||
entity_impl!(ElemIndex);
|
||||
@@ -172,7 +172,7 @@ entity_impl!(ArchivedElemIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub struct CustomSectionIndex(u32);
|
||||
entity_impl!(CustomSectionIndex);
|
||||
@@ -188,7 +188,7 @@ entity_impl!(ArchivedCustomSectionIndex);
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub enum ExportIndex {
|
||||
/// Function export.
|
||||
@@ -210,7 +210,7 @@ pub enum ExportIndex {
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "enable-rkyv",
|
||||
archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
archive_attr(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug))
|
||||
)]
|
||||
pub enum ImportIndex {
|
||||
/// Function import.
|
||||
|
||||
@@ -17,16 +17,17 @@ use indexmap::IndexMap;
|
||||
use loupe::MemoryUsage;
|
||||
#[cfg(feature = "enable-rkyv")]
|
||||
use rkyv::{
|
||||
de::SharedDeserializer, ser::Serializer, ser::SharedSerializer, Archive, Archived,
|
||||
Deserialize as RkyvDeserialize, Fallible, Serialize as RkyvSerialize,
|
||||
de::SharedDeserializeRegistry, ser::ScratchSpace, ser::Serializer,
|
||||
ser::SharedSerializeRegistry, Archive, Archived, Deserialize as RkyvDeserialize, Fallible,
|
||||
Serialize as RkyvSerialize,
|
||||
};
|
||||
#[cfg(feature = "enable-serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "enable-rkyv")]
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::iter::ExactSizeIterator;
|
||||
#[cfg(feature = "enable-rkyv")]
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -142,10 +143,10 @@ pub struct ArchivableModuleInfo {
|
||||
exports: ArchivableIndexMap<String, ExportIndex>,
|
||||
start_function: Option<FunctionIndex>,
|
||||
table_initializers: Vec<TableInitializer>,
|
||||
passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
|
||||
passive_data: HashMap<DataIndex, Arc<[u8]>>,
|
||||
passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
|
||||
passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
|
||||
global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
|
||||
function_names: HashMap<FunctionIndex, String>,
|
||||
function_names: BTreeMap<FunctionIndex, String>,
|
||||
signatures: PrimaryMap<SignatureIndex, FunctionType>,
|
||||
functions: PrimaryMap<FunctionIndex, SignatureIndex>,
|
||||
tables: PrimaryMap<TableIndex, TableType>,
|
||||
@@ -168,10 +169,10 @@ impl From<ModuleInfo> for ArchivableModuleInfo {
|
||||
exports: ArchivableIndexMap::from(it.exports),
|
||||
start_function: it.start_function,
|
||||
table_initializers: it.table_initializers,
|
||||
passive_elements: it.passive_elements,
|
||||
passive_data: it.passive_data,
|
||||
passive_elements: it.passive_elements.into_iter().collect(),
|
||||
passive_data: it.passive_data.into_iter().collect(),
|
||||
global_initializers: it.global_initializers,
|
||||
function_names: it.function_names,
|
||||
function_names: it.function_names.into_iter().collect(),
|
||||
signatures: it.signatures,
|
||||
functions: it.functions,
|
||||
tables: it.tables,
|
||||
@@ -197,10 +198,10 @@ impl From<ArchivableModuleInfo> for ModuleInfo {
|
||||
exports: it.exports.into(),
|
||||
start_function: it.start_function,
|
||||
table_initializers: it.table_initializers,
|
||||
passive_elements: it.passive_elements,
|
||||
passive_data: it.passive_data,
|
||||
passive_elements: it.passive_elements.into_iter().collect(),
|
||||
passive_data: it.passive_data.into_iter().collect(),
|
||||
global_initializers: it.global_initializers,
|
||||
function_names: it.function_names,
|
||||
function_names: it.function_names.into_iter().collect(),
|
||||
signatures: it.signatures,
|
||||
functions: it.functions,
|
||||
tables: it.tables,
|
||||
@@ -228,20 +229,22 @@ impl Archive for ModuleInfo {
|
||||
type Archived = <ArchivableModuleInfo as Archive>::Archived;
|
||||
type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
|
||||
|
||||
fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut MaybeUninit<Self::Archived>) {
|
||||
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
|
||||
ArchivableModuleInfo::from(self).resolve(pos, resolver, out)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "enable-rkyv")]
|
||||
impl<S: Serializer + SharedSerializer + ?Sized> RkyvSerialize<S> for ModuleInfo {
|
||||
impl<S: Serializer + SharedSerializeRegistry + ScratchSpace + ?Sized> RkyvSerialize<S>
|
||||
for ModuleInfo
|
||||
{
|
||||
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
|
||||
ArchivableModuleInfo::from(self).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "enable-rkyv")]
|
||||
impl<D: Fallible + ?Sized + SharedDeserializer> RkyvDeserialize<ModuleInfo, D>
|
||||
impl<D: Fallible + ?Sized + SharedDeserializeRegistry> RkyvDeserialize<ModuleInfo, D>
|
||||
for Archived<ModuleInfo>
|
||||
{
|
||||
fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
|
||||
|
||||
@@ -21,7 +21,7 @@ more-asserts = "0.2"
|
||||
cfg-if = "1.0"
|
||||
backtrace = "0.3"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
rkyv = { version = "0.6.1", optional = true}
|
||||
rkyv = { version = "0.7.20", optional = true }
|
||||
loupe = { version = "0.1", features = ["enable-indexmap"] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
|
||||
@@ -99,13 +99,16 @@ cfg_if::cfg_if! {
|
||||
unsafe fn thread_stack() -> (usize, usize) {
|
||||
let this_thread = libc::pthread_self();
|
||||
let mut thread_attrs: libc::pthread_attr_t = mem::zeroed();
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
libc::pthread_getattr_np(this_thread, &mut thread_attrs);
|
||||
#[cfg(target_os = "freebsd")]
|
||||
libc::pthread_attr_get_np(this_thread, &mut thread_attrs);
|
||||
let mut stackaddr: *mut libc::c_void = ptr::null_mut();
|
||||
let mut stacksize: libc::size_t = 0;
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
let ok = libc::pthread_getattr_np(this_thread, &mut thread_attrs);
|
||||
#[cfg(target_os = "freebsd")]
|
||||
let ok = libc::pthread_attr_get_np(this_thread, &mut thread_attrs);
|
||||
if ok == 0 {
|
||||
libc::pthread_attr_getstack(&thread_attrs, &mut stackaddr, &mut stacksize);
|
||||
libc::pthread_attr_destroy(&mut thread_attrs);
|
||||
}
|
||||
(stackaddr as usize, stacksize)
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.53
|
||||
1.56
|
||||
|
||||
44
tests/compilers/deterministic.rs
Normal file
44
tests/compilers/deterministic.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use anyhow::Result;
|
||||
use wasmer::{wat2wasm, Module};
|
||||
|
||||
fn compile_and_compare(wasm: &[u8]) -> Result<()> {
|
||||
let store = Default::default();
|
||||
|
||||
// compile for first time
|
||||
let module = Module::new(&store, wasm)?;
|
||||
let first = module.serialize()?;
|
||||
|
||||
// compile for second time
|
||||
let module = Module::new(&store, wasm)?;
|
||||
let second = module.serialize()?;
|
||||
|
||||
assert!(first == second);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deterministic_empty() -> Result<()> {
|
||||
let wasm_bytes = wat2wasm(
|
||||
br#"
|
||||
(module)
|
||||
"#,
|
||||
)?;
|
||||
|
||||
compile_and_compare(&wasm_bytes)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deterministic_table() -> Result<()> {
|
||||
let wasm_bytes = wat2wasm(
|
||||
br#"
|
||||
(module
|
||||
(table 2 funcref)
|
||||
(func $f1)
|
||||
(func $f2)
|
||||
(elem (i32.const 0) $f1 $f2))
|
||||
"#,
|
||||
)?;
|
||||
|
||||
compile_and_compare(&wasm_bytes)
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
extern crate compiler_test_derive;
|
||||
|
||||
mod config;
|
||||
mod deterministic;
|
||||
mod imports;
|
||||
mod issues;
|
||||
mod metering;
|
||||
|
||||
@@ -257,7 +257,9 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> {
|
||||
.err()
|
||||
.unwrap();
|
||||
match err {
|
||||
InstantiationError::Link(_) | InstantiationError::HostEnvInitialization(_) => {
|
||||
InstantiationError::Link(_)
|
||||
| InstantiationError::HostEnvInitialization(_)
|
||||
| InstantiationError::CpuFeature(_) => {
|
||||
panic!("It should be a start error")
|
||||
}
|
||||
InstantiationError::Start(err) => {
|
||||
|
||||
@@ -70,7 +70,7 @@ cranelift spec::simd::simd_i8x16_arith2
|
||||
cranelift spec::simd::simd_int_to_int_extend
|
||||
|
||||
# Windows doesn't overcommit and fails to allocate 4GB of memory
|
||||
windows wast::wasmer::max_size_of_memory
|
||||
windows wasmer::max_size_of_memory
|
||||
|
||||
# Frontends
|
||||
|
||||
|
||||
@@ -16,19 +16,14 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true }
|
||||
serde_bytes = { version = "0.11", optional = true }
|
||||
bincode = { version = "1.2", optional = true }
|
||||
loupe = "0.1"
|
||||
enumset = "1.0"
|
||||
|
||||
[features]
|
||||
# Enable the `compiler` feature if you want the engine to compile
|
||||
# and not be only on headless mode.
|
||||
default = ["serialize", "compiler"]
|
||||
compiler = [
|
||||
"wasmer-compiler/translator"
|
||||
]
|
||||
serialize = [
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"bincode"
|
||||
]
|
||||
compiler = ["wasmer-compiler/translator"]
|
||||
serialize = ["serde", "serde_bytes", "bincode"]
|
||||
|
||||
[badges]
|
||||
# TODO: publish this crate again and deprecate it
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
//! done as separate steps.
|
||||
|
||||
use crate::engine::DummyEngine;
|
||||
use enumset::EnumSet;
|
||||
use loupe::MemoryUsage;
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::CompileError;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::ModuleEnvironment;
|
||||
use wasmer_compiler::{CompileError, CpuFeature};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError, Tunables};
|
||||
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
|
||||
use wasmer_types::{
|
||||
@@ -30,6 +31,7 @@ pub struct DummyArtifactMetadata {
|
||||
// Plans for that module
|
||||
pub memory_styles: PrimaryMap<MemoryIndex, MemoryStyle>,
|
||||
pub table_styles: PrimaryMap<TableIndex, TableStyle>,
|
||||
pub cpu_features: u64,
|
||||
}
|
||||
|
||||
/// A Dummy artifact.
|
||||
@@ -104,6 +106,7 @@ impl DummyArtifact {
|
||||
data_initializers,
|
||||
memory_styles,
|
||||
table_styles,
|
||||
cpu_features: engine.target().cpu_features().as_u64(),
|
||||
};
|
||||
Self::from_parts(&engine, metadata)
|
||||
}
|
||||
@@ -211,6 +214,10 @@ impl Artifact for DummyArtifact {
|
||||
&self.metadata.features
|
||||
}
|
||||
|
||||
fn cpu_features(&self) -> EnumSet<CpuFeature> {
|
||||
EnumSet::from_u64(self.metadata.cpu_features)
|
||||
}
|
||||
|
||||
fn data_initializers(&self) -> &[OwnedDataInitializer] {
|
||||
&*self.metadata.data_initializers
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user