Merge branch 'master' into js-api-improvement

This commit is contained in:
Syrus Akbary
2021-11-24 23:58:00 +01:00
80 changed files with 988 additions and 1091 deletions

View File

@@ -1,4 +1,4 @@
[target.'cfg(target_os = "linux")'] [target.'cfg(all(target_os = "linux", target_env = "gnu"))']
rustflags = [ rustflags = [
# Put the VM functions in the dynamic symbol table. # Put the VM functions in the dynamic symbol table.
"-C", "link-arg=-Wl,-E", "-C", "link-arg=-Wl,-E",

View File

@@ -22,14 +22,14 @@ jobs:
- name: Install LLVM - name: Install LLVM
shell: bash shell: bash
run: | 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 }} 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 "${{ 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: env:
LLVM_DIR: ${{ github.workspace }}/llvm-11 LLVM_DIR: ${{ github.workspace }}/llvm-13
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'
- name: Build & package documentation - name: Build & package documentation
run: make package-docs run: make package-docs
- name: Publish documentation - name: Publish documentation

View File

@@ -23,11 +23,11 @@ jobs:
components: rustfmt, clippy components: rustfmt, clippy
- name: Install LLVM (Linux) - name: Install LLVM (Linux)
run: | 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 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-11 mkdir -p /opt/llvm-12
tar xf /opt/llvm.tar.gz --strip-components=1 -C /opt/llvm-11 tar xf /opt/llvm.tar.xz --strip-components=1 -C /opt/llvm-12
echo '/opt/llvm-11/bin' >> $GITHUB_PATH echo '/opt/llvm-12/bin' >> $GITHUB_PATH
echo 'LLVM_SYS_110_PREFIX=/opt/llvm-11' >> $GITHUB_ENV echo 'LLVM_SYS_120_PREFIX=/opt/llvm-12' >> $GITHUB_ENV
- run: make lint - run: make lint
env: env:
ENABLE_CRANELIFT: "1" ENABLE_CRANELIFT: "1"

View File

@@ -42,7 +42,7 @@ jobs:
include: include:
- build: linux-x64 - build: linux-x64
os: ubuntu-18.04 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' artifact_name: 'wasmer-linux-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_linux' cross_compilation_artifact_name: 'cross_compiled_from_linux'
run_test: true run_test: true
@@ -51,7 +51,7 @@ jobs:
use_sccache: true use_sccache: true
- build: macos-x64 - build: macos-x64
os: macos-11 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' artifact_name: 'wasmer-darwin-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_mac' cross_compilation_artifact_name: 'cross_compiled_from_mac'
run_test: true run_test: true
@@ -68,8 +68,8 @@ jobs:
run_test_capi: false run_test_capi: false
- build: windows-x64 - build: windows-x64
os: windows-latest os: windows-latest
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/windows-amd64.tar.gz' # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/12.x/windows-amd64.tar.gz'
llvm_choco_version: 12.0.1 llvm_choco_version: 13.0.0
artifact_name: 'wasmer-windows-amd64' artifact_name: 'wasmer-windows-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_win' cross_compilation_artifact_name: 'cross_compiled_from_win'
run_integration_tests: true run_integration_tests: true
@@ -80,7 +80,7 @@ jobs:
# os: [self-hosted, linux, ARM64] # os: [self-hosted, linux, ARM64]
# random_sccache_port: true # random_sccache_port: true
# use_sccache: 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' # artifact_name: 'wasmer-linux-aarch64'
# run_integration_tests: false # run_integration_tests: false
- build: linux-musl-x64 - build: linux-musl-x64
@@ -122,7 +122,7 @@ jobs:
choco install llvm --version ${{ matrix.llvm_choco_version }} --allow-downgrade choco install llvm --version ${{ matrix.llvm_choco_version }} --allow-downgrade
cd 'C:\Program Files\LLVM\' cd 'C:\Program Files\LLVM\'
LLVM_DIR=$(pwd) 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) - name: Install LLVM (macOS Apple Silicon)
if: matrix.os == 'macos-11.0' && !matrix.llvm_url if: matrix.os == 'macos-11.0' && !matrix.llvm_url
run: | run: |
@@ -131,12 +131,12 @@ jobs:
if: matrix.llvm_url if: matrix.llvm_url
shell: bash shell: bash
run: | 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 }} LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }}
mkdir ${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_DIR}/bin" >> $GITHUB_PATH
echo "LLVM_SYS_110_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV echo "LLVM_SYS_120_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
env: env:
LLVM_DIR: .llvm LLVM_DIR: .llvm
- name: Set up dependencies for Mac OS - name: Set up dependencies for Mac OS

54
Cargo.lock generated
View File

@@ -210,6 +210,27 @@ version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" 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]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.4.3"
@@ -1156,9 +1177,9 @@ dependencies = [
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "110.0.2" version = "120.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b7cc88ba864d592f52132ed3a19a97118fe16c92a63961f54b0ab7279c5407f" checksum = "b4a810627ac62b396f5fd2214ba9bbd8748d4d6efdc4d2c1c1303ea7a75763ce"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",
@@ -1773,22 +1794,33 @@ dependencies = [
] ]
[[package]] [[package]]
name = "rkyv" name = "rend"
version = "0.6.7" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb135b3e5e3311f0a254bfb00333f4bac9ef1d89888b84242a89eb8722b09a07" checksum = "6d0351a2e529ee30d571ef31faa5a4e0b9addaad087697b77efb20d2809e41c7"
dependencies = [ 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", "ptr_meta",
"rend",
"rkyv_derive", "rkyv_derive",
"seahash", "seahash",
] ]
[[package]] [[package]]
name = "rkyv_derive" name = "rkyv_derive"
version = "0.6.7" version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba8f489f6b6d8551bb15904293c1ad58a6abafa7d8390d15f7ed05a2afcd87d5" checksum = "2ae58c4ba80f15f2f0842f4c61729e92c4e33a09bd78196c2b1ab9b0771a3ddf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2723,7 +2755,6 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"paste", "paste",
"rayon",
"serde", "serde",
"thiserror", "thiserror",
"typetag", "typetag",
@@ -2901,6 +2932,7 @@ name = "wasmer-engine"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"enumset",
"lazy_static", "lazy_static",
"loupe", "loupe",
"memmap2", "memmap2",
@@ -2920,6 +2952,7 @@ name = "wasmer-engine-dummy"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"enumset",
"loupe", "loupe",
"serde", "serde",
"serde_bytes", "serde_bytes",
@@ -2934,6 +2967,7 @@ name = "wasmer-engine-dylib"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"enumset",
"leb128", "leb128",
"libloading", "libloading",
"loupe", "loupe",
@@ -2955,6 +2989,7 @@ version = "2.0.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"enumset",
"leb128", "leb128",
"libloading", "libloading",
"loupe", "loupe",
@@ -2973,6 +3008,7 @@ name = "wasmer-engine-universal"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"enumset",
"leb128", "leb128",
"loupe", "loupe",
"region", "region",

View File

@@ -134,24 +134,19 @@ ifneq ($(ENABLE_LLVM), 0)
LLVM_VERSION := $(shell llvm-config --version) LLVM_VERSION := $(shell llvm-config --version)
# If findstring is not empty, then it have found the value # If findstring is not empty, then it have found the value
ifneq (, $(findstring 12,$(LLVM_VERSION))) ifneq (, $(findstring 13,$(LLVM_VERSION)))
compilers += llvm compilers += llvm
else ifneq (, $(findstring 11,$(LLVM_VERSION))) else ifneq (, $(findstring 12,$(LLVM_VERSION)))
compilers += llvm
else ifneq (, $(findstring 10,$(LLVM_VERSION)))
compilers += llvm compilers += llvm
endif endif
# … or try to autodetect LLVM from `llvm-config-<version>`. # … or try to autodetect LLVM from `llvm-config-<version>`.
else 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) LLVM_VERSION := $(shell llvm-config-12 --version)
compilers += llvm 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 endif
endif endif

View File

@@ -57,3 +57,8 @@ required-features = ["universal", "cranelift"]
name = "dylib_cranelift" name = "dylib_cranelift"
path = "fuzz_targets/dylib_cranelift.rs" path = "fuzz_targets/dylib_cranelift.rs"
required-features = ["dylib", "cranelift"] required-features = ["dylib", "cranelift"]
[[bin]]
name = "deterministic"
path = "fuzz_targets/deterministic.rs"
required-features = ["universal", "dylib", "cranelift", "llvm", "singlepass"]

View 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,
//);
});

View File

@@ -1288,7 +1288,7 @@ mod inner {
#[test] #[test]
fn test_into_array() { fn test_into_array() {
assert_eq!(().into_array(), []); assert_eq!(().into_array(), [0i128; 0]);
assert_eq!((1).into_array(), [1]); assert_eq!((1).into_array(), [1]);
assert_eq!((1i32, 2i64).into_array(), [1, 2]); assert_eq!((1i32, 2i64).into_array(), [1, 2]);
assert_eq!( assert_eq!(

View File

@@ -1472,7 +1472,7 @@ mod inner {
#[test] #[test]
fn test_into_array() { fn test_into_array() {
assert_eq!(().into_array(), []); assert_eq!(().into_array(), [0i128; 0]);
assert_eq!((1).into_array(), [1]); assert_eq!((1).into_array(), [1]);
assert_eq!((1i32, 2i64).into_array(), [1, 2]); assert_eq!((1i32, 2i64).into_array(), [1, 2]);
assert_eq!( assert_eq!(

View File

@@ -58,6 +58,11 @@ pub enum InstantiationError {
#[error(transparent)] #[error(transparent)]
Start(RuntimeError), 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 occurred when initializing the host environment.
#[error(transparent)] #[error(transparent)]
HostEnvInitialization(HostEnvInitError), HostEnvInitialization(HostEnvInitError),
@@ -68,6 +73,7 @@ impl From<wasmer_engine::InstantiationError> for InstantiationError {
match other { match other {
wasmer_engine::InstantiationError::Link(e) => Self::Link(e), wasmer_engine::InstantiationError::Link(e) => Self::Link(e),
wasmer_engine::InstantiationError::Start(e) => Self::Start(e), wasmer_engine::InstantiationError::Start(e) => Self::Start(e),
wasmer_engine::InstantiationError::CpuFeature(e) => Self::CpuFeature(e),
} }
} }
} }

View File

@@ -42,7 +42,6 @@ serde = { version = "1", optional = true, features = ["derive"] }
thiserror = "1" thiserror = "1"
typetag = { version = "0.1", optional = true } typetag = { version = "0.1", optional = true }
paste = "1.0" paste = "1.0"
rayon = "1.5"
[dev-dependencies] [dev-dependencies]
field-offset = "0.3.3" field-offset = "0.3.3"

View File

@@ -103,12 +103,15 @@ int main(int argc, const char* argv[]) {
wasmer_last_error_message(error_message, error_length); wasmer_last_error_message(error_message, error_length);
printf("Attempted to set an immutable global: `%s`\n", error_message); 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_val_t some_set_value = WASM_F32_VAL(21);
wasm_global_set(some, &some_set_value); wasm_global_set(some, &some_set_value);
printf("`some` value: %.1f\n", some_value.of.f32); printf("`some` value: %.1f\n", some_value.of.f32);
wasm_globaltype_delete(one_type);
wasm_globaltype_delete(some_type);
wasm_module_delete(module); wasm_module_delete(module);
wasm_extern_vec_delete(&exports); wasm_extern_vec_delete(&exports);
wasm_instance_delete(instance); wasm_instance_delete(instance);

View File

@@ -63,6 +63,8 @@ int main(int argc, const char* argv[]) {
printf("Instantiating module...\n"); printf("Instantiating module...\n");
wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL); wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL);
wasm_func_delete(host_func);
wasm_global_delete(host_global);
if (!instance) { if (!instance) {
printf("> Error instantiating module!\n"); printf("> Error instantiating module!\n");

View File

@@ -15,6 +15,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); wasm_byte_vec_new(&wat, strlen(wat_string), wat_string);
wasm_byte_vec_t wasm_bytes; wasm_byte_vec_t wasm_bytes;
wat2wasm(&wat, &wasm_bytes); wat2wasm(&wat, &wasm_bytes);
wasm_byte_vec_delete(&wat);
printf("Creating the store...\n"); printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new(); wasm_engine_t* engine = wasm_engine_new();

View File

@@ -69,13 +69,7 @@ int main(int argc, const char* argv[]) {
// Instantiate. // Instantiate.
printf("Instantiating module...\n"); printf("Instantiating module...\n");
wasm_importtype_vec_t import_types;
wasm_module_imports(module, &import_types);
wasm_extern_vec_t imports; 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); bool get_imports_result = wasi_get_imports(store, module, wasi_env, &imports);
if (!get_imports_result) { if (!get_imports_result) {
@@ -153,6 +147,7 @@ int main(int argc, const char* argv[]) {
fclose(memory_stream); fclose(memory_stream);
printf("WASI Stdout: `%.*s`\n", (int) stdout_size, stdout); printf("WASI Stdout: `%.*s`\n", (int) stdout_size, stdout);
free(stdout);
} }

View File

@@ -49,13 +49,12 @@
use libc::{c_char, c_int}; use libc::{c_char, c_int};
use std::cell::RefCell; use std::cell::RefCell;
use std::error::Error; use std::fmt::Display;
use std::fmt::{self, Display, Formatter};
use std::ptr::{self, NonNull}; use std::ptr::{self, NonNull};
use std::slice; use std::slice;
thread_local! { 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. /// Rust function to register a new error.
@@ -63,24 +62,23 @@ thread_local! {
/// # Example /// # Example
/// ///
/// ```rust,no_run /// ```rust,no_run
/// # use wasmer::error::{update_last_error, CApiError}; /// # use wasmer::error::update_last_error;
/// ///
/// update_last_error(CApiError { /// update_last_error("Hello, World!");
/// msg: "Hello, World!".to_string(),
/// });
/// ``` /// ```
pub fn update_last_error<E: Error + 'static>(err: E) { pub fn update_last_error<E: Display>(err: E) {
LAST_ERROR.with(|prev| { 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. /// 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()) 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 /// This can be used to dynamically allocate a buffer with the correct number of
/// bytes needed to store a message. /// bytes needed to store a message.
@@ -88,10 +86,11 @@ pub(crate) fn take_last_error() -> Option<Box<dyn Error>> {
/// # Example /// # Example
/// ///
/// See this module's documentation to get a complete example. /// See this module's documentation to get a complete example.
// TODO(Amanieu): This should use size_t
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_last_error_length() -> c_int { pub extern "C" fn wasmer_last_error_length() -> c_int {
LAST_ERROR.with(|prev| match *prev.borrow() { 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, None => 0,
}) })
} }
@@ -118,6 +117,7 @@ pub extern "C" fn wasmer_last_error_length() -> c_int {
/// # Example /// # Example
/// ///
/// See this module's documentation to get a complete example. /// See this module's documentation to get a complete example.
// TODO(Amanieu): This should use size_t
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasmer_last_error_message( pub unsafe extern "C" fn wasmer_last_error_message(
buffer: Option<NonNull<c_char>>, 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 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 {}

View File

@@ -4,7 +4,6 @@
//! This resolver is used in the Wasm-C-API as the imports are provided //! This resolver is used in the Wasm-C-API as the imports are provided
//! by index and not by module and name. //! by index and not by module and name.
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
use std::iter::FromIterator; use std::iter::FromIterator;
use wasmer_api::{Export, Exportable, Extern, Resolver}; use wasmer_api::{Export, Exportable, Extern, Resolver};
@@ -26,16 +25,10 @@ impl Resolver for OrderedResolver {
impl FromIterator<Extern> for OrderedResolver { impl FromIterator<Extern> for OrderedResolver {
fn from_iter<I: IntoIterator<Item = Extern>>(iter: I) -> Self { fn from_iter<I: IntoIterator<Item = Extern>>(iter: I) -> Self {
OrderedResolver { let mut externs = Vec::new();
externs: iter.into_iter().collect(), for extern_ in iter {
} externs.push(extern_);
}
}
impl FromParallelIterator<Extern> for OrderedResolver {
fn from_par_iter<I: IntoParallelIterator<Item = Extern>>(iter: I) -> Self {
OrderedResolver {
externs: iter.into_par_iter().collect(),
} }
OrderedResolver { externs }
} }
} }

View File

@@ -9,7 +9,7 @@ pub use super::unstable::middlewares::wasm_config_push_middleware;
#[cfg(feature = "middlewares")] #[cfg(feature = "middlewares")]
use super::unstable::middlewares::wasmer_middleware_t; use super::unstable::middlewares::wasmer_middleware_t;
use super::unstable::target_lexicon::wasmer_target_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 cfg_if::cfg_if;
use std::sync::Arc; use std::sync::Arc;
use wasmer_api::Engine; use wasmer_api::Engine;
@@ -433,13 +433,8 @@ pub extern "C" fn wasm_engine_new_with_config(
config: Option<Box<wasm_config_t>>, config: Option<Box<wasm_config_t>>,
) -> Option<Box<wasm_engine_t>> { ) -> Option<Box<wasm_engine_t>> {
#[allow(dead_code)] #[allow(dead_code)]
fn return_with_error<M>(msg: M) -> Option<Box<wasm_engine_t>> fn return_with_error(msg: &str) -> Option<Box<wasm_engine_t>> {
where update_last_error(msg);
M: ToString,
{
update_last_error(CApiError {
msg: msg.to_string(),
});
return None; return None;
} }

View File

@@ -5,6 +5,7 @@ use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
use super::CApiExternTag; use super::CApiExternTag;
use std::convert::TryInto; use std::convert::TryInto;
use std::ffi::c_void; use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::sync::Arc; use std::sync::Arc;
use wasmer_api::{Function, RuntimeError, Val}; use wasmer_api::{Function, RuntimeError, Val};
@@ -27,16 +28,16 @@ impl wasm_func_t {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_func_callback_t = unsafe extern "C" fn( pub type wasm_func_callback_t = unsafe extern "C" fn(
args: *const wasm_val_vec_t, args: &wasm_val_vec_t,
results: *mut wasm_val_vec_t, results: &mut wasm_val_vec_t,
) -> *mut wasm_trap_t; ) -> Option<Box<wasm_trap_t>>;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_func_callback_with_env_t = unsafe extern "C" fn( pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
env: *mut c_void, env: *mut c_void,
args: *const wasm_val_vec_t, args: &wasm_val_vec_t,
results: *mut wasm_val_vec_t, results: &mut wasm_val_vec_t,
) -> *mut wasm_trap_t; ) -> Option<Box<wasm_trap_t>>;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void); 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); let trap = callback(&processed_args, &mut results);
if !trap.is_null() { if let Some(trap) = trap {
let trap: Box<wasm_trap_t> = Box::from_raw(trap);
return Err(trap.inner); return Err(trap.inner);
} }
let processed_results = results let processed_results = results
.into_slice() .take()
.expect("Failed to convert `results` into a slice")
.into_iter() .into_iter()
.map(TryInto::try_into) .map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>() .collect::<Result<Vec<Val>, _>>()
@@ -124,12 +122,8 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
impl Drop for WrapperEnv { impl Drop for WrapperEnv {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(env_finalizer) = if let Some(env_finalizer) = *self.env_finalizer {
Arc::get_mut(&mut self.env_finalizer).and_then(Option::take) unsafe { (env_finalizer)(self.env as _) }
{
if !self.env.is_null() {
unsafe { (env_finalizer)(self.env as _) }
}
} }
} }
} }
@@ -153,15 +147,12 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
let trap = callback(env.env, &processed_args, &mut results); let trap = callback(env.env, &processed_args, &mut results);
if !trap.is_null() { if let Some(trap) = trap {
let trap: Box<wasm_trap_t> = Box::from_raw(trap);
return Err(trap.inner); return Err(trap.inner);
} }
let processed_results = results let processed_results = results
.into_slice() .take()
.expect("Failed to convert `results` into a slice")
.into_iter() .into_iter()
.map(TryInto::try_into) .map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>() .collect::<Result<Vec<Val>, _>>()
@@ -201,39 +192,21 @@ pub unsafe extern "C" fn wasm_func_call(
let args = args?; let args = args?;
let params = args let params = args
.into_slice() .as_slice()
.map(|slice| { .iter()
slice .cloned()
.into_iter() .map(TryInto::try_into)
.map(TryInto::try_into) .collect::<Result<Vec<Val>, _>>()
.collect::<Result<Vec<Val>, _>>() .expect("Arguments conversion failed");
.expect("Arguments conversion failed")
})
.unwrap_or_default();
match func.inner.call(&params) { match func.inner.call(&params) {
Ok(wasm_results) => { Ok(wasm_results) => {
let vals = wasm_results for (slot, val) in results
.into_iter() .as_uninit_slice()
.map(TryInto::try_into) .iter_mut()
.collect::<Result<Vec<wasm_val_t>, _>>() .zip(wasm_results.into_iter())
.expect("Results conversion failed"); {
*slot = MaybeUninit::new(val.try_into().expect("Results conversion failed"));
// `results` is an uninitialized vector. Set a new value.
if results.is_uninitialized() {
*results = vals.into();
}
// `results` is an initialized but empty vector. Fill it
// item per item.
else {
let slice = results
.into_slice_mut()
.expect("`wasm_func_call`, results' size is greater than 0 but data is NULL");
for (result, value) in slice.iter_mut().zip(vals.iter()) {
(*result).kind = value.kind;
(*result).of = value.of;
}
} }
None None

View File

@@ -48,7 +48,6 @@ pub unsafe extern "C" fn wasm_global_new(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>) {} 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] #[no_mangle]
pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> { pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> {
// do shallow copy // do shallow copy

View File

@@ -38,7 +38,6 @@ pub unsafe extern "C" fn wasm_memory_new(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_delete(_memory: Option<Box<wasm_memory_t>>) {} 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] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> { pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> {
// do shallow copy // do shallow copy

View File

@@ -6,7 +6,7 @@ mod table;
pub use function::*; pub use function::*;
pub use global::*; pub use global::*;
pub use memory::*; pub use memory::*;
use std::mem; use std::mem::{self, ManuallyDrop};
pub use table::*; pub use table::*;
use wasmer_api::{Extern, ExternType}; use wasmer_api::{Extern, ExternType};
@@ -150,13 +150,23 @@ impl From<Extern> for wasm_extern_t {
} }
impl From<wasm_extern_t> for Extern { impl From<wasm_extern_t> for Extern {
fn from(other: wasm_extern_t) -> Self { fn from(mut other: wasm_extern_t) -> Self {
match other.get_tag() { let out = match other.get_tag() {
CApiExternTag::Function => unsafe { (&*other.inner.function.inner).clone().into() }, CApiExternTag::Function => unsafe {
CApiExternTag::Memory => unsafe { (&*other.inner.memory.inner).clone().into() }, (*ManuallyDrop::take(&mut other.inner.function).inner).into()
CApiExternTag::Table => unsafe { (&*other.inner.table.inner).clone().into() }, },
CApiExternTag::Global => unsafe { (&*other.inner.global.inner).clone().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
} }
} }

View File

@@ -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::module::wasm_module_t;
use super::store::wasm_store_t; use super::store::wasm_store_t;
use super::trap::wasm_trap_t; use super::trap::wasm_trap_t;
use crate::ordered_resolver::OrderedResolver; use crate::ordered_resolver::OrderedResolver;
use rayon::prelude::*;
use std::mem;
use std::sync::Arc; use std::sync::Arc;
use wasmer_api::{Extern, Instance, InstantiationError}; use wasmer_api::{Extern, Instance, InstantiationError};
@@ -42,7 +40,7 @@ pub unsafe extern "C" fn wasm_instance_new(
_store: Option<&wasm_store_t>, _store: Option<&wasm_store_t>,
module: Option<&wasm_module_t>, module: Option<&wasm_module_t>,
imports: Option<&wasm_extern_vec_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>> { ) -> Option<Box<wasm_instance_t>> {
let module = module?; let module = module?;
let imports = imports?; let imports = imports?;
@@ -51,10 +49,9 @@ pub unsafe extern "C" fn wasm_instance_new(
let module_imports = wasm_module.imports(); let module_imports = wasm_module.imports();
let module_import_count = module_imports.len(); let module_import_count = module_imports.len();
let resolver: OrderedResolver = imports let resolver: OrderedResolver = imports
.into_slice() .as_slice()
.map(|imports| imports.par_iter()) .iter()
.unwrap_or_else(|| [].par_iter()) .map(|imp| Extern::from(imp.as_ref().unwrap().as_ref().clone()))
.map(|imp| Extern::from((&**imp).clone()))
.take(module_import_count) .take(module_import_count)
.collect(); .collect();
@@ -68,8 +65,16 @@ pub unsafe extern "C" fn wasm_instance_new(
} }
Err(InstantiationError::Start(runtime_error)) => { Err(InstantiationError::Start(runtime_error)) => {
let this_trap: Box<wasm_trap_t> = Box::new(runtime_error.into()); if let Some(trap) = trap {
*trap = Box::into_raw(this_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; return None;
} }
@@ -182,17 +187,13 @@ pub unsafe extern "C" fn wasm_instance_exports(
out: &mut wasm_extern_vec_t, out: &mut wasm_extern_vec_t,
) { ) {
let instance = &instance.inner; let instance = &instance.inner;
let mut extern_vec = instance let extern_vec = instance
.exports .exports
.iter() .iter()
.map(|(_name, r#extern)| Box::into_raw(Box::new(r#extern.clone().into()))) .map(|(_name, r#extern)| Some(Box::new(r#extern.clone().into())))
.collect::<Vec<*mut wasm_extern_t>>(); .collect();
extern_vec.shrink_to_fit();
out.size = extern_vec.len(); out.set_buffer(extern_vec);
out.data = extern_vec.as_mut_ptr();
mem::forget(extern_vec);
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,13 +1,121 @@
#[doc(hidden)]
#[macro_export]
macro_rules! wasm_declare_vec_inner { 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) => { Read the documentation of [`", $c_ty, "`] to see more concrete examples.
paste::paste! {
#[doc = "Creates an empty vector of [`" $prefix "_" $name "_t`]. # 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 # Example
@@ -18,31 +126,89 @@ macro_rules! wasm_declare_vec_inner {
# #include \"tests/wasmer.h\" # #include \"tests/wasmer.h\"
# #
int main() { int main() {
// Creates an empty vector of `" $prefix "_" $name "_t`. // Creates an empty vector of `", $c_ty, "`.
" $prefix "_" $name "_vec_t vector; ", stringify!($name), " vector;
" $prefix "_" $name "_vec_new_empty(&vector); ", stringify!($empty), "(&vector);
// Check that it is empty. // Check that it is empty.
assert(vector.size == 0); assert(vector.size == 0);
// Free it. // Free it.
" $prefix "_" $name "_vec_delete(&vector); ", stringify!($delete), "(&vector);
return 0;
} }
# }) # })
# .success(); # .success();
# } # }
```"] ```")]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_empty>](out: *mut [<$prefix _ $name _vec_t>]) { pub extern "C" fn $empty(out: &mut $name) {
// TODO: actually implement this out.size = 0;
[<$prefix _ $name _vec_new_uninitialized>](out, 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 { macro_rules! wasm_declare_vec {
($name:ident) => { ($name:ident) => {
wasm_declare_vec!($name, wasm); wasm_declare_vec!($name, wasm);
@@ -50,218 +216,25 @@ macro_rules! wasm_declare_vec {
($name:ident, $prefix:ident) => { ($name:ident, $prefix:ident) => {
paste::paste! { paste::paste! {
#[doc = "Represents a vector of `" $prefix "_" $name "_t`. wasm_declare_vec_inner!(
name: [<$prefix _ $name _vec_t>],
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples. ty: [<$prefix _ $name _t>],
c_ty: stringify!([<$prefix _ $name _t>]),
# Example c_val: concat!("({ ",
stringify!([<$prefix _ $name _t>]), " foo;\n",
```rust "memset(&foo, 0, sizeof(foo));\n",
# use inline_c::assert_c; "foo;\n",
# fn main() { "})"),
# (assert_c! { new: [<$prefix _ $name _vec_new>],
# #include \"tests/wasmer.h\" empty: [<$prefix _ $name _vec_new_empty>],
# uninit: [<$prefix _ $name _vec_new_uninitialized>],
int main() { copy: [<$prefix _ $name _vec_copy>],
// Create a vector of 2 `" $prefix "_" $name "_t`. delete: [<$prefix _ $name _vec_delete>],
" $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>],
}
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 { macro_rules! wasm_declare_boxed_vec {
($name:ident) => { ($name:ident) => {
wasm_declare_boxed_vec!($name, wasm); wasm_declare_boxed_vec!($name, wasm);
@@ -269,223 +242,60 @@ macro_rules! wasm_declare_boxed_vec {
($name:ident, $prefix:ident) => { ($name:ident, $prefix:ident) => {
paste::paste! { paste::paste! {
#[doc = "Represents a vector of `" $prefix "_" $name "_t`. wasm_declare_vec_inner!(
name: [<$prefix _ $name _vec_t>],
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples."] ty: Option<Box<[<$prefix _ $name _t>]>>,
#[derive(Debug)] c_ty: stringify!([<$prefix _ $name _t>] *),
#[repr(C)] c_val: "NULL",
pub struct [<$prefix _ $name _vec_t>] { new: [<$prefix _ $name _vec_new>],
pub size: usize, empty: [<$prefix _ $name _vec_new_empty>],
pub data: *mut *mut [<$prefix _ $name _t>], 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 {
($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_rules! wasm_impl_copy {
#[macro_export]
macro_rules! wasm_declare_own {
($name:ident) => { ($name:ident) => {
wasm_declare_own!($name, $prefix); wasm_impl_copy!($name, wasm);
}; };
($name:ident, $prefix:ident) => { ($name:ident, $prefix:ident) => {
paste::paste! { paste::paste! {
#[repr(C)]
pub struct [<$prefix _ $name _t>] {}
#[no_mangle] #[no_mangle]
pub extern "C" fn [<$prefix _ $name _delete>](_arg: *mut [<$prefix _ $name _t>]) { pub extern "C" fn [<$prefix _ $name _copy>](src: Option<&[<$prefix _ $name _t>]>) -> Option<Box<[<$prefix _ $name _t>]>> {
todo!("in generated delete") 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 { macro_rules! c_try {
($expr:expr; otherwise $return:expr) => {{ ($expr:expr; otherwise $return:expr) => {{
let res: Result<_, _> = $expr; let res: Result<_, _> = $expr;

View File

@@ -23,7 +23,7 @@
/// Private Rust macros. /// Private Rust macros.
#[macro_use] #[macro_use]
pub mod macros; mod macros;
/// An engine drives the compilation and the runtime. /// An engine drives the compilation and the runtime.
/// ///

View File

@@ -1,9 +1,6 @@
use super::store::wasm_store_t; use super::store::wasm_store_t;
use super::types::{ use super::types::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t};
wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t, use crate::error::update_last_error;
wasm_importtype_vec_t,
};
use crate::error::{update_last_error, CApiError};
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::Arc; use std::sync::Arc;
use wasmer_api::Module; use wasmer_api::Module;
@@ -36,8 +33,7 @@ pub unsafe extern "C" fn wasm_module_new(
let store = store?; let store = store?;
let bytes = bytes?; let bytes = bytes?;
let bytes = bytes.into_slice()?; let module = c_try!(Module::from_binary(&store.inner, bytes.as_slice()));
let module = c_try!(Module::from_binary(&store.inner, bytes));
Some(Box::new(wasm_module_t { Some(Box::new(wasm_module_t {
inner: Arc::new(module), inner: Arc::new(module),
@@ -107,12 +103,7 @@ pub unsafe extern "C" fn wasm_module_validate(
None => return false, None => return false,
}; };
let bytes = match bytes.into_slice() { if let Err(error) = Module::validate(&store.inner, bytes.as_slice()) {
Some(bytes) => bytes,
None => return false,
};
if let Err(error) = Module::validate(&store.inner, bytes) {
update_last_error(error); update_last_error(error);
false false
@@ -238,11 +229,10 @@ pub unsafe extern "C" fn wasm_module_exports(
let exports = module let exports = module
.inner .inner
.exports() .exports()
.map(Into::into) .map(|export| Some(Box::new(export.into())))
.map(Box::new) .collect();
.collect::<Vec<Box<wasm_exporttype_t>>>();
*out = exports.into(); out.set_buffer(exports);
} }
/// Returns an array of the imported types in the module. /// 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 let imports = module
.inner .inner
.imports() .imports()
.map(Into::into) .map(|import| Some(Box::new(import.into())))
.map(Box::new) .collect();
.collect::<Vec<Box<wasm_importtype_t>>>();
*out = imports.into(); out.set_buffer(imports);
} }
/// Deserializes a serialized module binary into a `wasm_module_t`. /// Deserializes a serialized module binary into a `wasm_module_t`.
@@ -472,21 +461,11 @@ pub unsafe extern "C" fn wasm_module_imports(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_module_deserialize( pub unsafe extern "C" fn wasm_module_deserialize(
store: &wasm_store_t, store: &wasm_store_t,
bytes: *const wasm_byte_vec_t, bytes: Option<&wasm_byte_vec_t>,
) -> Option<NonNull<wasm_module_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() { let module = c_try!(Module::deserialize(&store.inner, bytes.as_slice()));
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));
Some(NonNull::new_unchecked(Box::into_raw(Box::new( Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_module_t { wasm_module_t {
@@ -503,10 +482,7 @@ pub unsafe extern "C" fn wasm_module_deserialize(
/// ///
/// See [`wasm_module_deserialize`]. /// See [`wasm_module_deserialize`].
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_module_serialize( pub unsafe extern "C" fn wasm_module_serialize(module: &wasm_module_t, out: &mut wasm_byte_vec_t) {
module: &wasm_module_t,
out_ptr: &mut wasm_byte_vec_t,
) {
let byte_vec = match module.inner.serialize() { let byte_vec = match module.inner.serialize() {
Ok(byte_vec) => byte_vec, Ok(byte_vec) => byte_vec,
Err(err) => { Err(err) => {
@@ -514,7 +490,7 @@ pub unsafe extern "C" fn wasm_module_serialize(
return; return;
} }
}; };
*out_ptr = byte_vec.into(); out.set_buffer(byte_vec);
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -28,7 +28,7 @@ pub unsafe extern "C" fn wasm_trap_new(
_store: &mut wasm_store_t, _store: &mut wasm_store_t,
message: &wasm_message_t, message: &wasm_message_t,
) -> Option<Box<wasm_trap_t>> { ) -> Option<Box<wasm_trap_t>> {
let message_bytes = message.into_slice()?; let message_bytes = message.as_slice();
// The trap message is typed with `wasm_message_t` which is a // The trap message is typed with `wasm_message_t` which is a
// typeref to `wasm_name_t` with the exception that it's 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(); let mut byte_vec = message.into_bytes();
byte_vec.push(0); byte_vec.push(0);
let byte_vec: wasm_byte_vec_t = byte_vec.into(); out.set_buffer(byte_vec);
out.size = byte_vec.size;
out.data = byte_vec.data;
} }
/// Gets the origin frame attached to the trap. /// 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, out: &mut wasm_frame_vec_t,
) { ) {
let frames = trap.inner.trace(); let frames = trap.inner.trace();
let frame_vec: wasm_frame_vec_t = frames.into(); out.set_buffer(
frames
out.size = frame_vec.size; .iter()
out.data = frame_vec.data; .map(|frame| Some(Box::new(frame.into())))
.collect(),
);
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -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; use wasmer_api::ExportType;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[derive(Clone)]
pub struct wasm_exporttype_t { pub struct wasm_exporttype_t {
name: owned_wasm_name_t, name: wasm_name_t,
extern_type: Box<wasm_externtype_t>, extern_type: wasm_externtype_t,
} }
wasm_declare_boxed_vec!(exporttype); wasm_declare_boxed_vec!(exporttype);
wasm_impl_copy_delete!(exporttype);
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_exporttype_new( pub extern "C" fn wasm_exporttype_new(
name: Option<&wasm_name_t>, name: &wasm_name_t,
extern_type: Option<Box<wasm_externtype_t>>, extern_type: Box<wasm_externtype_t>,
) -> Option<Box<wasm_exporttype_t>> { ) -> Box<wasm_exporttype_t> {
let name = unsafe { owned_wasm_name_t::new(name?) }; Box::new(wasm_exporttype_t {
Some(Box::new(wasm_exporttype_t { name: name.clone(),
name, extern_type: *extern_type,
extern_type: extern_type?, })
}))
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_exporttype_name(export_type: &wasm_exporttype_t) -> &wasm_name_t { 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] #[no_mangle]
pub extern "C" fn wasm_exporttype_type(export_type: &wasm_exporttype_t) -> &wasm_externtype_t { 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 { impl From<ExportType> for wasm_exporttype_t {
fn from(other: ExportType) -> Self { fn from(other: ExportType) -> Self {
(&other).into() (&other).into()
@@ -43,8 +40,8 @@ impl From<ExportType> for wasm_exporttype_t {
impl From<&ExportType> for wasm_exporttype_t { impl From<&ExportType> for wasm_exporttype_t {
fn from(other: &ExportType) -> Self { fn from(other: &ExportType) -> Self {
let name: owned_wasm_name_t = other.name().to_string().into(); let name: wasm_name_t = other.name().to_string().into();
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into()); let extern_type: wasm_externtype_t = other.ty().into();
wasm_exporttype_t { name, extern_type } wasm_exporttype_t { name, extern_type }
} }

View File

@@ -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}; use wasmer_api::{ExternType, FunctionType, ValType};
#[derive(Debug)]
pub(crate) struct WasmFunctionType { pub(crate) struct WasmFunctionType {
pub(crate) function_type: FunctionType, pub(crate) function_type: FunctionType,
params: Box<wasm_valtype_vec_t>, params: wasm_valtype_vec_t,
results: Box<wasm_valtype_vec_t>, results: wasm_valtype_vec_t,
} }
impl WasmFunctionType { impl WasmFunctionType {
pub(crate) fn new(function_type: FunctionType) -> Self { pub(crate) fn new(function_type: FunctionType) -> Self {
let params: Box<wasm_valtype_vec_t> = Box::new(function_type.params().into()); let params: Vec<_> = function_type
let results: Box<wasm_valtype_vec_t> = Box::new(function_type.results().into()); .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 { Self {
function_type, function_type,
params, params: params.into(),
results, 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)] #[allow(non_camel_case_types)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[repr(transparent)] #[repr(transparent)]
@@ -52,6 +66,7 @@ impl wasm_functype_t {
} }
wasm_declare_boxed_vec!(functype); wasm_declare_boxed_vec!(functype);
wasm_impl_copy_delete!(functype);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_new( pub unsafe extern "C" fn wasm_functype_new(
@@ -62,44 +77,29 @@ pub unsafe extern "C" fn wasm_functype_new(
let results = results?; let results = results?;
let params_as_valtype: Vec<ValType> = params let params_as_valtype: Vec<ValType> = params
.into_slice()? .take()
.into_iter() .into_iter()
.map(|val| val.as_ref().into()) .map(|val| val.as_ref().unwrap().as_ref().into())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let results_as_valtype: Vec<ValType> = results let results_as_valtype: Vec<ValType> = results
.into_slice()? .take()
.iter() .into_iter()
.map(|val| val.as_ref().into()) .map(|val| val.as_ref().unwrap().as_ref().into())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
wasm_valtype_vec_delete(Some(params));
wasm_valtype_vec_delete(Some(results));
Some(Box::new(wasm_functype_t::new(FunctionType::new( Some(Box::new(wasm_functype_t::new(FunctionType::new(
params_as_valtype, params_as_valtype,
results_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] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_params( pub unsafe extern "C" fn wasm_functype_params(
function_type: Option<&wasm_functype_t>, function_type: Option<&wasm_functype_t>,
) -> Option<&wasm_valtype_vec_t> { ) -> Option<&wasm_valtype_vec_t> {
let function_type = function_type?; let function_type = function_type?;
Some(function_type.inner().params.as_ref()) Some(&function_type.inner().params)
} }
#[no_mangle] #[no_mangle]
@@ -108,5 +108,5 @@ pub unsafe extern "C" fn wasm_functype_results(
) -> Option<&wasm_valtype_vec_t> { ) -> Option<&wasm_valtype_vec_t> {
let function_type = function_type?; let function_type = function_type?;
Some(function_type.inner().results.as_ref()) Some(&function_type.inner().results)
} }

View File

@@ -8,12 +8,12 @@ use wasmer_api::{ExternType, GlobalType};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct WasmGlobalType { pub(crate) struct WasmGlobalType {
pub(crate) global_type: GlobalType, pub(crate) global_type: GlobalType,
content: Box<wasm_valtype_t>, content: wasm_valtype_t,
} }
impl WasmGlobalType { impl WasmGlobalType {
pub(crate) fn new(global_type: GlobalType) -> Self { pub(crate) fn new(global_type: GlobalType) -> Self {
let content = Box::new(global_type.ty.into()); let content = global_type.ty.into();
Self { Self {
global_type, global_type,
@@ -79,5 +79,5 @@ pub unsafe extern "C" fn wasm_globaltype_mutability(
pub unsafe extern "C" fn wasm_globaltype_content( pub unsafe extern "C" fn wasm_globaltype_content(
global_type: &wasm_globaltype_t, global_type: &wasm_globaltype_t,
) -> &wasm_valtype_t { ) -> &wasm_valtype_t {
global_type.inner().content.as_ref() &global_type.inner().content
} }

View File

@@ -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; use wasmer_api::ImportType;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[derive(Clone)]
#[repr(C)] #[repr(C)]
pub struct wasm_importtype_t { pub struct wasm_importtype_t {
module: owned_wasm_name_t, module: wasm_name_t,
name: owned_wasm_name_t, name: wasm_name_t,
extern_type: Box<wasm_externtype_t>, extern_type: wasm_externtype_t,
} }
wasm_declare_boxed_vec!(importtype); wasm_declare_boxed_vec!(importtype);
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_importtype_new( pub extern "C" fn wasm_importtype_new(
module: Option<&wasm_name_t>, module: Option<Box<wasm_name_t>>,
name: Option<&wasm_name_t>, name: Option<Box<wasm_name_t>>,
extern_type: Option<Box<wasm_externtype_t>>, extern_type: Option<Box<wasm_externtype_t>>,
) -> Option<Box<wasm_importtype_t>> { ) -> Option<Box<wasm_importtype_t>> {
let (module, name) = unsafe {
(
owned_wasm_name_t::new(module?),
owned_wasm_name_t::new(name?),
)
};
Some(Box::new(wasm_importtype_t { Some(Box::new(wasm_importtype_t {
name, name: *name?,
module, module: *module?,
extern_type: extern_type?, extern_type: *extern_type?,
})) }))
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_importtype_module(import_type: &wasm_importtype_t) -> &wasm_name_t { 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] #[no_mangle]
pub extern "C" fn wasm_importtype_name(import_type: &wasm_importtype_t) -> &wasm_name_t { 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] #[no_mangle]
pub extern "C" fn wasm_importtype_type(import_type: &wasm_importtype_t) -> &wasm_externtype_t { 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] #[no_mangle]
@@ -57,9 +51,9 @@ impl From<ImportType> for wasm_importtype_t {
impl From<&ImportType> for wasm_importtype_t { impl From<&ImportType> for wasm_importtype_t {
fn from(other: &ImportType) -> Self { fn from(other: &ImportType) -> Self {
let module: owned_wasm_name_t = other.module().to_string().into(); let module: wasm_name_t = other.module().to_string().into();
let name: owned_wasm_name_t = other.name().to_string().into(); let name: wasm_name_t = other.name().to_string().into();
let extern_type: Box<wasm_externtype_t> = Box::new(other.ty().into()); let extern_type: wasm_externtype_t = other.ty().into();
wasm_importtype_t { wasm_importtype_t {
module, module,

View File

@@ -4,18 +4,18 @@ use wasmer_api::{ExternType, MemoryType, Pages};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct WasmMemoryType { pub(crate) struct WasmMemoryType {
pub(crate) memory_type: MemoryType, pub(crate) memory_type: MemoryType,
limits: Box<wasm_limits_t>, limits: wasm_limits_t,
} }
impl WasmMemoryType { impl WasmMemoryType {
pub(crate) fn new(memory_type: MemoryType) -> Self { 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 _, min: memory_type.minimum.0 as _,
max: memory_type max: memory_type
.maximum .maximum
.map(|max| max.0 as _) .map(|max| max.0 as _)
.unwrap_or(LIMITS_MAX_SENTINEL), .unwrap_or(LIMITS_MAX_SENTINEL),
}); };
Self { Self {
memory_type, memory_type,
@@ -79,5 +79,5 @@ const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_limits(memory_type: &wasm_memorytype_t) -> &wasm_limits_t { 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
} }

View File

@@ -28,63 +28,9 @@ wasm_declare_vec!(byte);
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_name_t = wasm_byte_vec_t; pub type wasm_name_t = wasm_byte_vec_t;
impl AsRef<wasm_name_t> for wasm_name_t { impl From<String> for wasm_name_t {
fn as_ref(&self) -> &wasm_name_t {
&self
}
}
/// An owned version of `wasm_name_t`.
///
/// Assumes that data is either valid host-owned or null.
// NOTE: `wasm_name_t` already does a deep copy, so we just derive `Clone` here.
#[derive(Debug, Clone)]
#[repr(transparent)]
#[allow(non_camel_case_types)]
pub struct owned_wasm_name_t(wasm_name_t);
impl owned_wasm_name_t {
/// Take ownership of some `wasm_name_t`
///
/// # Safety
/// You must ensure that the data pointed to by `wasm_name_t` is valid and
/// that it is not owned by anyone else.
pub unsafe fn new(name: &wasm_name_t) -> Self {
Self(wasm_name_t {
size: name.size,
data: name.data,
})
}
}
impl Drop for owned_wasm_name_t {
fn drop(&mut self) {
if !self.0.data.is_null() {
let _v = unsafe { Vec::from_raw_parts(self.0.data, self.0.size, self.0.size) };
self.0.data = std::ptr::null_mut();
self.0.size = 0;
}
// why can't we call this function?
//unsafe { crate::wasm_c_api::macros::wasm_byte_vec_delete(Some(self.0)) }
}
}
impl AsRef<wasm_name_t> for owned_wasm_name_t {
fn as_ref(&self) -> &wasm_name_t {
&self.0
}
}
impl From<String> for owned_wasm_name_t {
fn from(string: String) -> Self { fn from(string: String) -> Self {
let mut boxed_str: Box<str> = string.into_boxed_str(); string.into_bytes().into()
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)
} }
} }

View File

@@ -10,21 +10,21 @@ const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct WasmTableType { pub(crate) struct WasmTableType {
pub(crate) table_type: TableType, pub(crate) _table_type: TableType,
limits: Box<wasm_limits_t>, limits: wasm_limits_t,
content: Box<wasm_valtype_t>, content: wasm_valtype_t,
} }
impl WasmTableType { impl WasmTableType {
pub(crate) fn new(table_type: TableType) -> Self { 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 _, min: table_type.minimum as _,
max: table_type.maximum.unwrap_or(LIMITS_MAX_SENTINEL), max: table_type.maximum.unwrap_or(LIMITS_MAX_SENTINEL),
}); };
let content = Box::new(table_type.ty.into()); let content = table_type.ty.into();
Self { Self {
table_type, _table_type: table_type,
limits, limits,
content, content,
} }
@@ -79,12 +79,12 @@ pub unsafe extern "C" fn wasm_tabletype_new(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_limits(table_type: &wasm_tabletype_t) -> &wasm_limits_t { 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] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_element(table_type: &wasm_tabletype_t) -> &wasm_valtype_t { 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] #[no_mangle]

View File

@@ -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 /// 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 // own
name: &wasm_name_t, name: &wasm_name_t,
) -> bool { ) -> bool {
let name = match name.into_slice() { let name = match str::from_utf8(name.as_slice()) {
Some(name) => match str::from_utf8(name) { Ok(name) => name,
Ok(name) => name, Err(_) => return false, // not ideal!
Err(_) => return false, // not ideal!
},
None => return false,
}; };
match Arc::get_mut(&mut module.inner) { match Arc::get_mut(&mut module.inner) {

View File

@@ -54,7 +54,6 @@
//! ``` //! ```
use super::super::types::wasm_name_t; use super::super::types::wasm_name_t;
use crate::error::CApiError;
use enumset::EnumSet; use enumset::EnumSet;
use std::slice; use std::slice;
use std::str::{self, FromStr}; use std::str::{self, FromStr};
@@ -153,7 +152,7 @@ pub unsafe extern "C" fn wasmer_triple_new(
))); )));
Some(Box::new(wasmer_triple_t { 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)),
})) }))
} }

View File

@@ -2,13 +2,9 @@
//! API. //! API.
use super::super::{ use super::super::{
externals::wasm_extern_t, externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t,
module::wasm_module_t,
store::wasm_store_t,
types::{owned_wasm_name_t, wasm_name_t},
wasi::wasi_env_t, wasi::wasi_env_t,
}; };
use crate::error::CApiError;
use wasmer_api::Extern; use wasmer_api::Extern;
use wasmer_wasi::{generate_import_object_from_env, get_wasi_version}; 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)] #[allow(non_camel_case_types)]
#[derive(Clone)] #[derive(Clone)]
pub struct wasmer_named_extern_t { pub struct wasmer_named_extern_t {
module: owned_wasm_name_t, module: wasm_name_t,
name: owned_wasm_name_t, name: wasm_name_t,
r#extern: Box<wasm_extern_t>, r#extern: Box<wasm_extern_t>,
} }
@@ -121,7 +117,7 @@ mod __cbindgen_hack__ {
pub extern "C" fn wasmer_named_extern_module( pub extern "C" fn wasmer_named_extern_module(
named_extern: Option<&wasmer_named_extern_t>, named_extern: Option<&wasmer_named_extern_t>,
) -> Option<&wasm_name_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`. /// 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( pub extern "C" fn wasmer_named_extern_name(
named_extern: Option<&wasmer_named_extern_t>, named_extern: Option<&wasmer_named_extern_t>,
) -> Option<&wasm_name_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 /// 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 store = &store.inner;
let version = c_try!( let version = c_try!(get_wasi_version(&module.inner, false)
get_wasi_version(&module.inner, false).ok_or_else(|| CApiError { .ok_or("could not detect a WASI version on the given module"));
msg: "could not detect a WASI version on the given module".to_string(),
})
);
let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);
*imports = import_object imports.set_buffer(
.into_iter() import_object
.map(|((module, name), export)| { .into_iter()
let module = module.into(); .map(|((module, name), export)| {
let name = name.into(); let module = module.into();
let extern_inner = Extern::from_vm_export(store, export); 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, module,
name, name,
r#extern: Box::new(extern_inner.into()), r#extern: Box::new(extern_inner.into()),
}))
}) })
}) .collect::<Vec<_>>(),
.collect::<Vec<_>>() );
.into();
Some(()) Some(())
} }

View File

@@ -1,5 +1,5 @@
use super::types::{wasm_ref_t, wasm_valkind_enum}; use super::types::{wasm_ref_t, wasm_valkind_enum};
use crate::error::{update_last_error, CApiError}; use crate::error::update_last_error;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use wasmer_api::Val; 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] #[no_mangle]
pub unsafe extern "C" fn wasm_val_copy( pub unsafe extern "C" fn wasm_val_copy(
// own // own
@@ -147,7 +156,7 @@ pub unsafe extern "C" fn wasm_val_copy(
}, },
Err(e) => { Err(e) => {
update_last_error(CApiError { msg: e.to_string() }); update_last_error(e);
return; return;
} }

View File

@@ -11,7 +11,7 @@ use super::{
module::wasm_module_t, module::wasm_module_t,
store::wasm_store_t, store::wasm_store_t,
}; };
use crate::error::{update_last_error, CApiError}; use crate::error::update_last_error;
use std::cmp::min; use std::cmp::min;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ffi::CStr; use std::ffi::CStr;
@@ -212,9 +212,7 @@ pub unsafe extern "C" fn wasi_env_read_stdout(
if let Some(stdout) = stdout.as_mut() { if let Some(stdout) = stdout.as_mut() {
stdout stdout
} else { } else {
update_last_error(CApiError { update_last_error("could not find a file handle for `stdout`");
msg: "could not find a file handle for `stdout`".to_string(),
});
return -1; return -1;
} }
} else { } else {
@@ -235,15 +233,11 @@ pub unsafe extern "C" fn wasi_env_read_stderr(
if let Some(stderr) = stderr.as_mut() { if let Some(stderr) = stderr.as_mut() {
stderr stderr
} else { } else {
update_last_error(CApiError { update_last_error("could not find a file handle for `stderr`");
msg: "could not find a file handle for `stderr`".to_string(),
});
return -1; return -1;
} }
} else { } else {
update_last_error(CApiError { update_last_error("could not find a file handle for `stderr`");
msg: "could not find a file handle for `stderr`".to_string(),
});
return -1; return -1;
}; };
read_inner(stderr, inner_buffer) read_inner(stderr, inner_buffer)
@@ -348,33 +342,29 @@ fn wasi_get_imports_inner(
let store = &store.inner; let store = &store.inner;
let version = c_try!( let version = c_try!(get_wasi_version(&module.inner, false)
get_wasi_version(&module.inner, false).ok_or_else(|| CApiError { .ok_or("could not detect a WASI version on the given module"));
msg: "could not detect a WASI version on the given module".to_string(),
})
);
let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version);
*imports = module imports.set_buffer(c_try!(module
.inner .inner
.imports() .imports()
.map(|import_type| { .map(|import_type| {
let export = c_try!(import_object let export = import_object
.resolve_by_name(import_type.module(), import_type.name()) .resolve_by_name(import_type.module(), import_type.name())
.ok_or_else(|| CApiError { .ok_or_else(|| {
msg: format!( format!(
"Failed to resolve import \"{}\" \"{}\"", "Failed to resolve import \"{}\" \"{}\"",
import_type.module(), import_type.module(),
import_type.name() import_type.name()
), )
})); })?;
let inner = Extern::from_vm_export(store, export); let inner = Extern::from_vm_export(store, export);
Some(Box::new(inner.into())) Ok(Some(Box::new(inner.into())))
}) })
.collect::<Option<Vec<_>>>()? .collect::<Result<Vec<_>, String>>()));
.into();
Some(()) Some(())
} }

View File

@@ -11,16 +11,8 @@ use super::types::wasm_byte_vec_t;
#[cfg(feature = "wat")] #[cfg(feature = "wat")]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t, out: &mut wasm_byte_vec_t) { pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t, out: &mut wasm_byte_vec_t) {
let wat: &[u8] = match wat.into_slice() { match wasmer_api::wat2wasm(wat.as_slice()) {
Some(v) => v, Ok(val) => out.set_buffer(val.into_owned()),
_ => {
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(),
Err(err) => { Err(err) => {
crate::error::update_last_error(err); crate::error::update_last_error(err);
out.data = std::ptr::null_mut(); 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; return;
} }
}; };
*out = result;
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -25,9 +25,9 @@ more-asserts = "0.2"
gimli = { version = "0.25", optional = true } gimli = { version = "0.25", optional = true }
smallvec = "1.6" smallvec = "1.6"
loupe = "0.1" loupe = "0.1"
target-lexicon = { version = "0.12.2", default-features = false }
[dev-dependencies] [dev-dependencies]
target-lexicon = { version = "0.12.2", default-features = false }
cranelift-codegen = { version = "0.76", features = ["all-arch"] } cranelift-codegen = { version = "0.76", features = ["all-arch"] }
lazy_static = "1.4" lazy_static = "1.4"

View File

@@ -21,6 +21,7 @@ use gimli::write::{Address, EhFrame, FrameTable};
use loupe::MemoryUsage; use loupe::MemoryUsage;
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use std::sync::Arc; use std::sync::Arc;
use target_lexicon::{Architecture, OperatingSystem};
use wasmer_compiler::CompileError; use wasmer_compiler::CompileError;
use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target};
use wasmer_compiler::{ use wasmer_compiler::{
@@ -29,14 +30,12 @@ use wasmer_compiler::{
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
SectionIndex, SectionIndex,
}; };
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
use wasmer_compiler::{ use wasmer_compiler::{
CustomSection, CustomSectionProtection, Relocation, RelocationKind, RelocationTarget, CustomSection, CustomSectionProtection, Relocation, RelocationKind, RelocationTarget,
SectionBody, SectionBody,
}; };
use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex};
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
use wasmer_vm::libcalls::LibCall; use wasmer_vm::libcalls::LibCall;
/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// 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. // FDEs will cause some issues in Linux.
None None
} else { } else {
use std::sync::Mutex;
match target.triple().default_calling_convention() { match target.triple().default_calling_convention() {
Ok(CallingConvention::SystemV) => { Ok(CallingConvention::SystemV) => {
match isa.create_systemv_cie() { match isa.create_systemv_cie() {
Some(cie) => { Some(cie) => {
let mut dwarf_frametable = FrameTable::default(); let mut dwarf_frametable = FrameTable::default();
let cie_id = dwarf_frametable.add_cie(cie); 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 // Even though we are in a SystemV system, Cranelift doesn't support it
None => None, None => None,
@@ -111,30 +109,36 @@ impl Compiler for CraneliftCompiler {
let mut custom_sections = PrimaryMap::new(); 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
let probestack_trampoline = CustomSection { == OperatingSystem::Linux
protection: CustomSectionProtection::ReadExecute, && target.triple().architecture == Architecture::X86_64
// We create a jump to an absolute 64bits address {
// with an indrect jump immediatly followed but the absolute address let probestack_trampoline = CustomSection {
// JMP [IP+0] FF 25 00 00 00 00 protection: CustomSectionProtection::ReadExecute,
// 64bits ADDR 00 00 00 00 00 00 00 00 preset to 0 until the relocation takes place // We create a jump to an absolute 64bits address
bytes: SectionBody::new_with_vec(vec![ // with an indrect jump immediatly followed but the absolute address
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 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
relocations: vec![Relocation { bytes: SectionBody::new_with_vec(vec![
kind: RelocationKind::Abs8, 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
reloc_target: RelocationTarget::LibCall(LibCall::Probestack), 0x00,
// 6 is the size of the jmp instruction. The relocated address must follow ]),
offset: 6, relocations: vec![Relocation {
addend: 0, kind: RelocationKind::Abs8,
}], reloc_target: RelocationTarget::LibCall(LibCall::Probestack),
}; // 6 is the size of the jmp instruction. The relocated address must follow
#[cfg(all(target_arch = "x86_64", target_os = "linux"))] offset: 6,
custom_sections.push(probestack_trampoline); addend: 0,
#[cfg(all(target_arch = "x86_64", target_os = "linux"))] }],
let probestack_trampoline_relocation_target = SectionIndex::new(custom_sections.len() - 1); };
custom_sections.push(probestack_trampoline);
let functions = function_body_inputs Some(SectionIndex::new(custom_sections.len() - 1))
} else {
None
};
let (functions, fdes): (Vec<CompiledFunction>, Vec<_>) = function_body_inputs
.iter() .iter()
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>() .collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
.par_iter() .par_iter()
@@ -170,12 +174,8 @@ impl Compiler for CraneliftCompiler {
)?; )?;
let mut code_buf: Vec<u8> = Vec::new(); let mut code_buf: Vec<u8> = Vec::new();
let mut reloc_sink = RelocSink::new( let mut reloc_sink =
&module, RelocSink::new(&module, func_index, probestack_trampoline_relocation_target);
func_index,
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
probestack_trampoline_relocation_target,
);
let mut trap_sink = TrapSink::new(); let mut trap_sink = TrapSink::new();
let mut stackmap_sink = binemit::NullStackMapSink {}; let mut stackmap_sink = binemit::NullStackMapSink {};
context context
@@ -190,31 +190,31 @@ impl Compiler for CraneliftCompiler {
CompileError::Codegen(pretty_error(&context.func, Some(&*isa), error)) 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")] #[cfg(feature = "unwind")]
CraneliftUnwindInfo::FDE(fde) => { CraneliftUnwindInfo::FDE(fde) => {
if let Some((dwarf_frametable, cie_id)) = &dwarf_frametable { if dwarf_frametable.is_some() {
dwarf_frametable let fde = fde.to_fde(Address::Symbol {
.lock() // The symbol is the kind of relocation.
.expect("Can't write into DWARF frametable") // "0" is used for functions
.add_fde( symbol: WriterRelocate::FUNCTION_SYMBOL,
*cie_id, // We use the addend as a way to specify the
fde.to_fde(Address::Symbol { // function index
// The symbol is the kind of relocation. addend: i.index() as _,
// "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 // The unwind information is inserted into the dwarf section
Some(CompiledFunctionUnwindInfo::Dwarf) (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde))
} else { } 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(); let range = reader.range();
@@ -223,40 +223,41 @@ impl Compiler for CraneliftCompiler {
// We transform the Cranelift JumpTable's into compiler JumpTables // We transform the Cranelift JumpTable's into compiler JumpTables
let func_jt_offsets = transform_jump_table(context.func.jt_offsets); let func_jt_offsets = transform_jump_table(context.func.jt_offsets);
Ok(CompiledFunction { Ok((
body: FunctionBody { CompiledFunction {
body: code_buf, body: FunctionBody {
unwind_info, body: code_buf,
unwind_info,
},
jt_offsets: func_jt_offsets,
relocations: reloc_sink.func_relocs,
frame_info: CompiledFunctionFrameInfo {
address_map,
traps: trap_sink.traps,
},
}, },
jt_offsets: func_jt_offsets, fde,
relocations: reloc_sink.func_relocs, ))
frame_info: CompiledFunctionFrameInfo {
address_map,
traps: trap_sink.traps,
},
})
}) })
.collect::<Result<Vec<_>, CompileError>>()? .collect::<Result<Vec<_>, CompileError>>()?
.into_iter() .into_iter()
.collect::<PrimaryMap<LocalFunctionIndex, _>>(); .unzip();
#[cfg(feature = "unwind")] #[cfg(feature = "unwind")]
let dwarf = { let dwarf = if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable {
let dwarf = if let Some((dwarf_frametable, _cie_id)) = dwarf_frametable { for fde in fdes {
let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok())); if let Some(fde) = fde {
dwarf_frametable dwarf_frametable.add_fde(cie_id, fde);
.lock() }
.unwrap() }
.write_eh_frame(&mut eh_frame) let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok()));
.unwrap(); dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap();
let eh_frame_section = eh_frame.0.into_section(); let eh_frame_section = eh_frame.0.into_section();
custom_sections.push(eh_frame_section); custom_sections.push(eh_frame_section);
Some(Dwarf::new(SectionIndex::new(custom_sections.len() - 1))) Some(Dwarf::new(SectionIndex::new(custom_sections.len() - 1)))
} else { } else {
None None
};
dwarf
}; };
#[cfg(not(feature = "unwind"))] #[cfg(not(feature = "unwind"))]
let dwarf = None; let dwarf = None;
@@ -289,7 +290,7 @@ impl Compiler for CraneliftCompiler {
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>(); .collect::<PrimaryMap<FunctionIndex, FunctionBody>>();
Ok(Compilation::new( Ok(Compilation::new(
functions, functions.into_iter().collect(),
custom_sections, custom_sections,
function_call_trampolines, function_call_trampolines,
dynamic_function_trampolines, dynamic_function_trampolines,

View File

@@ -2,12 +2,10 @@
use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind};
use cranelift_codegen::binemit; use cranelift_codegen::binemit;
#[cfg(target_arch = "x86_64")]
use cranelift_codegen::ir::LibCall; use cranelift_codegen::ir::LibCall;
use cranelift_codegen::ir::{self, ExternalName}; use cranelift_codegen::ir::{self, ExternalName};
use cranelift_entity::EntityRef as CraneliftEntityRef; use cranelift_entity::EntityRef as CraneliftEntityRef;
use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation}; use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation};
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
use wasmer_compiler::{RelocationKind, SectionIndex}; use wasmer_compiler::{RelocationKind, SectionIndex};
use wasmer_types::entity::EntityRef; use wasmer_types::entity::EntityRef;
use wasmer_types::{FunctionIndex, LocalFunctionIndex, ModuleInfo}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, ModuleInfo};
@@ -24,8 +22,7 @@ pub(crate) struct RelocSink<'a> {
pub func_relocs: Vec<Relocation>, pub func_relocs: Vec<Relocation>,
/// The section where the probestack trampoline call is located /// The section where the probestack trampoline call is located
#[cfg(all(target_arch = "x86_64", target_os = "linux"))] pub probestack_trampoline_relocation_target: Option<SectionIndex>,
pub probestack_trampoline_relocation_target: SectionIndex,
} }
impl<'a> binemit::RelocSink for RelocSink<'a> { 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"), .expect("The provided function should be local"),
) )
} else if let ExternalName::LibCall(libcall) = *name { } else if let ExternalName::LibCall(libcall) = *name {
match libcall { match (libcall, self.probestack_trampoline_relocation_target) {
#[cfg(all(target_arch = "x86_64", target_os = "linux"))] (LibCall::Probestack, Some(probestack_trampoline_relocation_target)) => {
LibCall::Probestack => {
self.func_relocs.push(Relocation { self.func_relocs.push(Relocation {
kind: RelocationKind::X86CallPCRel4, kind: RelocationKind::X86CallPCRel4,
reloc_target: RelocationTarget::CustomSection( reloc_target: RelocationTarget::CustomSection(
self.probestack_trampoline_relocation_target, probestack_trampoline_relocation_target,
), ),
offset: offset, offset: offset,
addend: addend, addend: addend,
@@ -100,8 +96,7 @@ impl<'a> RelocSink<'a> {
pub fn new( pub fn new(
module: &'a ModuleInfo, module: &'a ModuleInfo,
func_index: FunctionIndex, func_index: FunctionIndex,
#[cfg(all(target_arch = "x86_64", target_os = "linux"))] probestack_trampoline_relocation_target: Option<SectionIndex>,
probestack_trampoline_relocation_target: SectionIndex,
) -> Self { ) -> Self {
let local_func_index = module let local_func_index = module
.local_func_index(func_index) .local_func_index(func_index)
@@ -110,7 +105,6 @@ impl<'a> RelocSink<'a> {
module, module,
local_func_index, local_func_index,
func_relocs: Vec::new(), func_relocs: Vec::new(),
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
probestack_trampoline_relocation_target, probestack_trampoline_relocation_target,
} }
} }

View File

@@ -28,7 +28,7 @@ loupe = "0.1"
package = "inkwell" package = "inkwell"
version = "0.1.0-beta.4" version = "0.1.0-beta.4"
default-features = false default-features = false
features = ["llvm11-0", "target-x86", "target-aarch64"] features = ["llvm12-0", "target-x86", "target-aarch64"]
[build-dependencies] [build-dependencies]
cc = "1.0" cc = "1.0"

View File

@@ -24,14 +24,14 @@ to native speeds.
## Requirements ## Requirements
The LLVM compiler requires a valid installation of LLVM in your system. 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: You can install LLVM easily on your Debian-like system via this command:
```bash ```bash
wget https://apt.llvm.org/llvm.sh -O /tmp/llvm.sh 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: Or in macOS:

View File

@@ -4,7 +4,7 @@ use inkwell::{
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
builder::Builder, builder::Builder,
context::Context, context::Context,
types::{BasicMetadataTypeEnum, BasicType, FunctionType, StructType}, types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue}, values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue},
AddressSpace, AddressSpace,
}; };
@@ -206,17 +206,16 @@ impl Abi for Aarch64SystemV {
.map(|&ty| type_to_llvm(intrinsics, ty)) .map(|&ty| type_to_llvm(intrinsics, ty))
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
let sret = context let sret = context.struct_type(&basic_types, false);
.struct_type(&basic_types, false) let sret_ptr = sret.ptr_type(AddressSpace::Generic);
.ptr_type(AddressSpace::Generic);
let param_types = 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![( let mut attributes = vec![(
context.create_enum_attribute( context.create_type_attribute(
Attribute::get_named_enum_kind_id("sret"), Attribute::get_named_enum_kind_id("sret"),
0, sret.as_any_type_enum(),
), ),
AttributeLoc::Param(0), AttributeLoc::Param(0),
)]; )];

View File

@@ -4,7 +4,7 @@ use inkwell::{
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
builder::Builder, builder::Builder,
context::Context, context::Context,
types::{BasicMetadataTypeEnum, BasicType, FunctionType, StructType}, types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
values::{ values::{
BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue, BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue,
PointerValue, VectorValue, PointerValue, VectorValue,
@@ -263,14 +263,17 @@ impl Abi for X86_64SystemV {
.map(|&ty| type_to_llvm(intrinsics, ty)) .map(|&ty| type_to_llvm(intrinsics, ty))
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
let sret = context let sret = context.struct_type(&basic_types, false);
.struct_type(&basic_types, false) let sret_ptr = sret.ptr_type(AddressSpace::Generic);
.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![( 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), AttributeLoc::Param(0),
)]; )];
attributes.append(&mut vmctx_attributes(1)); attributes.append(&mut vmctx_attributes(1));

View File

@@ -1,6 +1,6 @@
use crate::address_map::get_function_address_map; use crate::address_map::get_function_address_map;
use crate::{common_decl::*, config::Singlepass, emitter_x64::*, machine::Machine, x64_decl::*}; 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 smallvec::{smallvec, SmallVec};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::iter; use std::iter;
@@ -22,6 +22,8 @@ use wasmer_types::{
}; };
use wasmer_vm::{MemoryStyle, TableStyle, TrapCode, VMBuiltinFunctionIndex, VMOffsets}; use wasmer_vm::{MemoryStyle, TableStyle, TrapCode, VMBuiltinFunctionIndex, VMOffsets};
type Assembler = VecAssembler<X64Relocation>;
/// The singlepass per-function code generator. /// The singlepass per-function code generator.
pub struct FuncGen<'a> { pub struct FuncGen<'a> {
// Immutable properties assigned at creation time. // Immutable properties assigned at creation time.
@@ -89,6 +91,9 @@ pub struct FuncGen<'a> {
/// ///
// Ordered by increasing InstructionAddressMap::srcloc. // Ordered by increasing InstructionAddressMap::srcloc.
instructions_address_map: Vec<InstructionAddressMap>, instructions_address_map: Vec<InstructionAddressMap>,
/// Calling convention to use.
calling_convention: CallingConvention,
} }
struct SpecialLabelSet { struct SpecialLabelSet {
@@ -1010,7 +1015,7 @@ impl<'a> FuncGen<'a> {
self.machine.state.stack_values.push(content); 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 { let stack_padding: usize = match calling_convention {
CallingConvention::WindowsFastcall => 32, CallingConvention::WindowsFastcall => 32,
@@ -1756,7 +1761,7 @@ impl<'a> FuncGen<'a> {
&mut self.assembler, &mut self.assembler,
self.local_types.len(), self.local_types.len(),
self.signature.params().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. // 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>, _table_styles: &'a PrimaryMap<TableIndex, TableStyle>,
local_func_index: LocalFunctionIndex, local_func_index: LocalFunctionIndex,
local_types_excluding_arguments: &[WpType], local_types_excluding_arguments: &[WpType],
calling_convention: CallingConvention,
) -> Result<FuncGen<'a>, CodegenError> { ) -> Result<FuncGen<'a>, CodegenError> {
let func_index = module.func_index(local_func_index); let func_index = module.func_index(local_func_index);
let sig_index = module.functions[func_index]; let sig_index = module.functions[func_index];
@@ -1844,7 +1850,7 @@ impl<'a> FuncGen<'a> {
.collect(), .collect(),
); );
let mut assembler = Assembler::new().unwrap(); let mut assembler = Assembler::new(0);
let special_labels = SpecialLabelSet { let special_labels = SpecialLabelSet {
integer_division_by_zero: assembler.get_label(), integer_division_by_zero: assembler.get_label(),
heap_access_oob: assembler.get_label(), heap_access_oob: assembler.get_label(),
@@ -1874,6 +1880,7 @@ impl<'a> FuncGen<'a> {
special_labels, special_labels,
src_loc: 0, src_loc: 0,
instructions_address_map: vec![], instructions_address_map: vec![],
calling_convention,
}; };
fg.emit_head()?; fg.emit_head()?;
Ok(fg) Ok(fg)
@@ -5404,7 +5411,7 @@ impl<'a> FuncGen<'a> {
self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize; self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize;
let vmcaller_checked_anyfunc_vmctx = let vmcaller_checked_anyfunc_vmctx =
self.vmoffsets.vmcaller_checked_anyfunc_vmctx() as usize; 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( self.emit_call_native(
|this| { |this| {
@@ -6698,7 +6705,7 @@ impl<'a> FuncGen<'a> {
self.machine.finalize_locals( self.machine.finalize_locals(
&mut self.assembler, &mut self.assembler,
&self.locals, &self.locals,
self.config.calling_convention, self.calling_convention,
); );
self.assembler.emit_mov( self.assembler.emit_mov(
Size::S64, Size::S64,
@@ -8811,7 +8818,7 @@ pub fn gen_std_trampoline(
sig: &FunctionType, sig: &FunctionType,
calling_convention: CallingConvention, calling_convention: CallingConvention,
) -> FunctionBody { ) -> FunctionBody {
let mut a = Assembler::new().unwrap(); let mut a = Assembler::new(0);
// Calculate stack offset. // Calculate stack offset.
let mut stack_offset: u32 = 0; let mut stack_offset: u32 = 0;
@@ -8921,7 +8928,7 @@ pub fn gen_std_dynamic_import_trampoline(
sig: &FunctionType, sig: &FunctionType,
calling_convention: CallingConvention, calling_convention: CallingConvention,
) -> FunctionBody { ) -> FunctionBody {
let mut a = Assembler::new().unwrap(); let mut a = Assembler::new(0);
// Allocate argument array. // 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 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, sig: &FunctionType,
calling_convention: CallingConvention, calling_convention: CallingConvention,
) -> CustomSection { ) -> CustomSection {
let mut a = Assembler::new().unwrap(); let mut a = Assembler::new(0);
// TODO: ARM entry trampoline is not emitted. // TODO: ARM entry trampoline is not emitted.

View File

@@ -13,7 +13,7 @@ use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::{ use wasmer_compiler::{
Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo, Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo,
CompiledFunction, Compiler, CompilerConfig, FunctionBinaryReader, FunctionBody, CompiledFunction, Compiler, CompilerConfig, CpuFeature, FunctionBinaryReader, FunctionBody,
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation, ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation,
}; };
@@ -62,8 +62,15 @@ impl Compiler for SinglepassCompiler {
OperatingSystem::Windows.to_string(), OperatingSystem::Windows.to_string(),
)); ));
}*/ }*/
if let Architecture::X86_32(arch) = target.triple().architecture { if target.triple().architecture != Architecture::X86_64 {
return Err(CompileError::UnsupportedTarget(arch.to_string())); 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 { if compile_info.features.multi_value {
return Err(CompileError::UnsupportedFeature("multivalue".to_string())); return Err(CompileError::UnsupportedFeature("multivalue".to_string()));
@@ -125,6 +132,7 @@ impl Compiler for SinglepassCompiler {
&table_styles, &table_styles,
i, i,
&locals, &locals,
calling_convention,
) )
.map_err(to_compile_error)?; .map_err(to_compile_error)?;

View File

@@ -4,9 +4,7 @@
use crate::compiler::SinglepassCompiler; use crate::compiler::SinglepassCompiler;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::{ use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target};
CallingConvention, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target,
};
use wasmer_types::Features; use wasmer_types::Features;
#[derive(Debug, Clone, MemoryUsage)] #[derive(Debug, Clone, MemoryUsage)]
@@ -15,8 +13,6 @@ pub struct Singlepass {
pub(crate) enable_stack_check: bool, pub(crate) enable_stack_check: bool,
/// The middleware chain. /// The middleware chain.
pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>, pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
#[loupe(skip)]
pub(crate) calling_convention: CallingConvention,
} }
impl Singlepass { impl Singlepass {
@@ -27,12 +23,6 @@ impl Singlepass {
enable_nan_canonicalization: true, enable_nan_canonicalization: true,
enable_stack_check: false, enable_stack_check: false,
middlewares: vec![], 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"),
},
} }
} }

View File

@@ -1,6 +1,10 @@
pub use crate::x64_decl::{GPR, XMM}; pub use crate::x64_decl::{GPR, XMM};
use dynasm::dynasm; 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. /// 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 /// `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 { macro_rules! jmp_op {
($ins:ident, $assembler:tt, $label:ident) => { ($ins:ident, $assembler:tt, $label:ident) => {
dynasm!($assembler ; $ins =>$label); dynasm!($assembler ; $ins =>$label)
} }
} }

View File

@@ -586,12 +586,14 @@ impl Machine {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use dynasmrt::x64::Assembler; use dynasmrt::x64::X64Relocation;
use dynasmrt::VecAssembler;
type Assembler = VecAssembler<X64Relocation>;
#[test] #[test]
fn test_release_locations_keep_state_nopanic() { fn test_release_locations_keep_state_nopanic() {
let mut machine = Machine::new(); let mut machine = Machine::new();
let mut assembler = Assembler::new().unwrap(); let mut assembler = Assembler::new(0);
let locs = machine.acquire_locations( let locs = machine.acquire_locations(
&mut assembler, &mut assembler,
&(0..10) &(0..10)

View File

@@ -20,8 +20,8 @@ hashbrown = { version = "0.11", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true } serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "1.0" thiserror = "1.0"
serde_bytes = { version = "0.11", optional = true } serde_bytes = { version = "0.11", optional = true }
smallvec = "1.6" smallvec = "1.6"
rkyv = { version = "0.6.1", optional = true } rkyv = { version = "0.7.20", optional = true }
loupe = "0.1" loupe = "0.1"
[features] [features]

View File

@@ -22,7 +22,7 @@ use wasmer_types::entity::entity_impl;
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, MemoryUsage)]
pub struct SectionIndex(u32); pub struct SectionIndex(u32);

View File

@@ -23,8 +23,9 @@ leb128 = "0.2"
libloading = "0.7" libloading = "0.7"
tempfile = "3.1" tempfile = "3.1"
which = "4.0" which = "4.0"
rkyv = "0.6.1" rkyv = "0.7.20"
loupe = "0.1" loupe = "0.1"
enumset = "1.0"
[features] [features]
# Enable the `compiler` feature if you want the engine to compile # Enable the `compiler` feature if you want the engine to compile

View File

@@ -3,6 +3,7 @@
use crate::engine::{DylibEngine, DylibEngineInner}; use crate::engine::{DylibEngine, DylibEngineInner};
use crate::serialize::{ArchivedModuleMetadata, ModuleMetadata}; use crate::serialize::{ArchivedModuleMetadata, ModuleMetadata};
use enumset::EnumSet;
use libloading::{Library, Symbol as LibrarySymbol}; use libloading::{Library, Symbol as LibrarySymbol};
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::error::Error; use std::error::Error;
@@ -17,8 +18,8 @@ use tracing::log::error;
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use tracing::trace; use tracing::trace;
use wasmer_compiler::{ use wasmer_compiler::{
Architecture, CompileError, CompiledFunctionFrameInfo, Features, FunctionAddressMap, Architecture, CompileError, CompiledFunctionFrameInfo, CpuFeature, Features,
OperatingSystem, Symbol, SymbolRegistry, Triple, FunctionAddressMap, OperatingSystem, Symbol, SymbolRegistry, Triple,
}; };
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use wasmer_compiler::{ use wasmer_compiler::{
@@ -211,6 +212,7 @@ impl DylibArtifact {
prefix: engine_inner.get_prefix(&data), prefix: engine_inner.get_prefix(&data),
data_initializers, data_initializers,
function_body_lengths, function_body_lengths,
cpu_features: target.cpu_features().as_u64(),
}; };
let serialized_data = metadata.serialize()?; let serialized_data = metadata.serialize()?;
@@ -800,6 +802,10 @@ impl Artifact for DylibArtifact {
&self.metadata.compile_info.features &self.metadata.compile_info.features
} }
fn cpu_features(&self) -> enumset::EnumSet<CpuFeature> {
EnumSet::from_u64(self.metadata.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] { fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.metadata.data_initializers &*self.metadata.data_initializers
} }

View File

@@ -1,10 +1,8 @@
use loupe::MemoryUsage; use loupe::MemoryUsage;
use rkyv::{ use rkyv::{
archived_value, archived_value, de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer,
de::{adapters::SharedDeserializerAdapter, deserializers::AllocDeserializer}, ser::Serializer as RkyvSerializer, Archive, Deserialize as RkyvDeserialize,
ser::adapters::SharedSerializerAdapter, Serialize as RkyvSerialize,
ser::{serializers::WriteSerializer, Serializer as RkyvSerializer},
Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::error::Error; use std::error::Error;
@@ -35,6 +33,7 @@ pub struct ModuleMetadata {
pub data_initializers: Box<[OwnedDataInitializer]>, pub data_initializers: Box<[OwnedDataInitializer]>,
// The function body lengths (used to find function by address) // The function body lengths (used to find function by address)
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>, pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
pub cpu_features: u64,
} }
pub struct ModuleMetadataSymbolRegistry<'a> { pub struct ModuleMetadataSymbolRegistry<'a> {
@@ -59,11 +58,11 @@ impl ModuleMetadata {
} }
pub fn serialize(&mut self) -> Result<Vec<u8>, CompileError> { 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 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()); 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> { pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
@@ -86,7 +85,7 @@ impl ModuleMetadata {
pub fn deserialize_from_archive( pub fn deserialize_from_archive(
archived: &ArchivedModuleMetadata, archived: &ArchivedModuleMetadata,
) -> Result<Self, DeserializeError> { ) -> Result<Self, DeserializeError> {
let mut deserializer = SharedDeserializerAdapter::new(AllocDeserializer); let mut deserializer = SharedDeserializeMap::new();
RkyvDeserialize::deserialize(archived, &mut deserializer) RkyvDeserialize::deserialize(archived, &mut deserializer)
.map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e))) .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
} }

View File

@@ -24,6 +24,7 @@ leb128 = "0.2"
libloading = "0.7" libloading = "0.7"
tempfile = "3.1" tempfile = "3.1"
loupe = "0.1" loupe = "0.1"
enumset = "1.0"
[features] [features]
# Enable the `compiler` feature if you want the engine to compile # Enable the `compiler` feature if you want the engine to compile

View File

@@ -3,12 +3,15 @@
use crate::engine::{StaticlibEngine, StaticlibEngineInner}; use crate::engine::{StaticlibEngine, StaticlibEngineInner};
use crate::serialize::{ModuleMetadata, ModuleMetadataSymbolRegistry}; use crate::serialize::{ModuleMetadata, ModuleMetadataSymbolRegistry};
use enumset::EnumSet;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::error::Error; use std::error::Error;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::{CompileError, Features, OperatingSystem, SymbolRegistry, Triple}; use wasmer_compiler::{
CompileError, CpuFeature, Features, OperatingSystem, SymbolRegistry, Triple,
};
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use wasmer_compiler::{ use wasmer_compiler::{
CompileModuleInfo, Compiler, FunctionBodyData, ModuleEnvironment, ModuleMiddlewareChain, CompileModuleInfo, Compiler, FunctionBodyData, ModuleEnvironment, ModuleMiddlewareChain,
@@ -46,6 +49,7 @@ pub struct StaticlibArtifact {
/// Length of the serialized metadata /// Length of the serialized metadata
metadata_length: usize, metadata_length: usize,
symbol_registry: ModuleMetadataSymbolRegistry, symbol_registry: ModuleMetadataSymbolRegistry,
is_compiled: bool,
} }
#[allow(dead_code)] #[allow(dead_code)]
@@ -181,6 +185,7 @@ impl StaticlibArtifact {
prefix: engine_inner.get_prefix(&data), prefix: engine_inner.get_prefix(&data),
data_initializers, data_initializers,
function_body_lengths, function_body_lengths,
cpu_features: target.cpu_features().as_u64(),
}; };
/* /*
@@ -295,6 +300,7 @@ impl StaticlibArtifact {
func_data_registry: engine_inner.func_data().clone(), func_data_registry: engine_inner.func_data().clone(),
metadata_length, metadata_length,
symbol_registry, symbol_registry,
is_compiled: true,
}) })
} }
@@ -415,6 +421,7 @@ impl StaticlibArtifact {
func_data_registry, func_data_registry,
metadata_length: 0, metadata_length: 0,
symbol_registry, symbol_registry,
is_compiled: false,
}) })
} }
@@ -450,6 +457,10 @@ impl Artifact for StaticlibArtifact {
&self.metadata.compile_info.features &self.metadata.compile_info.features
} }
fn cpu_features(&self) -> EnumSet<CpuFeature> {
EnumSet::from_u64(self.metadata.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] { fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.metadata.data_initializers &*self.metadata.data_initializers
} }
@@ -483,6 +494,12 @@ impl Artifact for StaticlibArtifact {
} }
fn preinstantiate(&self) -> Result<(), InstantiationError> { 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(()) Ok(())
} }

View File

@@ -12,6 +12,7 @@ pub struct ModuleMetadata {
pub data_initializers: Box<[OwnedDataInitializer]>, pub data_initializers: Box<[OwnedDataInitializer]>,
// The function body lengths (used to find function by address) // The function body lengths (used to find function by address)
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>, pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
pub cpu_features: u64,
} }
#[derive(MemoryUsage)] #[derive(MemoryUsage)]

View File

@@ -11,16 +11,22 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasmer-types = { path = "../types", version = "2.0.0", features = ["enable-rkyv"] } wasmer-types = { path = "../types", version = "2.0.0", features = [
wasmer-compiler = { path = "../compiler", version = "2.0.0", features = ["translator", "enable-rkyv"] } "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-vm = { path = "../vm", version = "2.0.0", features = ["enable-rkyv"] }
wasmer-engine = { path = "../engine", version = "2.0.0" } wasmer-engine = { path = "../engine", version = "2.0.0" }
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" } # flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
region = "3.0" region = "3.0"
cfg-if = "1.0" cfg-if = "1.0"
leb128 = "0.2" leb128 = "0.2"
rkyv = "0.6.1" rkyv = "0.7.20"
loupe = "0.1" loupe = "0.1"
enumset = "1.0"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winnt", "impl-default"] } winapi = { version = "0.3", features = ["winnt", "impl-default"] }

View File

@@ -6,9 +6,10 @@ use crate::link::link_module;
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use crate::serialize::SerializableCompilation; use crate::serialize::SerializableCompilation;
use crate::serialize::SerializableModule; use crate::serialize::SerializableModule;
use enumset::EnumSet;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use wasmer_compiler::{CompileError, Features, Triple}; use wasmer_compiler::{CompileError, CpuFeature, Features, Triple};
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment, ModuleMiddlewareChain}; use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment, ModuleMiddlewareChain};
use wasmer_engine::{ use wasmer_engine::{
@@ -128,6 +129,7 @@ impl UniversalArtifact {
compilation: serializable_compilation, compilation: serializable_compilation,
compile_info, compile_info,
data_initializers, data_initializers,
cpu_features: engine.target().cpu_features().as_u64(),
}; };
Self::from_parts(&mut inner_engine, serializable) Self::from_parts(&mut inner_engine, serializable)
} }
@@ -307,6 +309,10 @@ impl Artifact for UniversalArtifact {
&self.serializable.compile_info.features &self.serializable.compile_info.features
} }
fn cpu_features(&self) -> EnumSet<CpuFeature> {
EnumSet::from_u64(self.serializable.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] { fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.serializable.data_initializers &*self.serializable.data_initializers
} }

View File

@@ -1,10 +1,8 @@
use loupe::MemoryUsage; use loupe::MemoryUsage;
use rkyv::{ use rkyv::{
archived_value, archived_value, de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer,
de::{adapters::SharedDeserializerAdapter, deserializers::AllocDeserializer}, ser::Serializer as RkyvSerializer, Archive, Deserialize as RkyvDeserialize,
ser::adapters::SharedSerializerAdapter, Serialize as RkyvSerialize,
ser::{serializers::WriteSerializer, Serializer as RkyvSerializer},
Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize,
}; };
use wasmer_compiler::{ use wasmer_compiler::{
CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody,
@@ -38,6 +36,7 @@ pub struct SerializableModule {
pub compilation: SerializableCompilation, pub compilation: SerializableCompilation,
pub compile_info: CompileModuleInfo, pub compile_info: CompileModuleInfo,
pub data_initializers: Box<[OwnedDataInitializer]>, pub data_initializers: Box<[OwnedDataInitializer]>,
pub cpu_features: u64,
} }
fn to_serialize_error(err: impl std::error::Error) -> SerializeError { fn to_serialize_error(err: impl std::error::Error) -> SerializeError {
@@ -49,13 +48,13 @@ impl SerializableModule {
/// The bytes will have the following format: /// The bytes will have the following format:
/// RKYV serialization (any length) + POS (8 bytes) /// RKYV serialization (any length) + POS (8 bytes)
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> { 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 let pos = serializer
.serialize_value(self) .serialize_value(self)
.map_err(to_serialize_error)? as u64; .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()); serialized_data.extend_from_slice(&pos.to_le_bytes());
Ok(serialized_data) Ok(serialized_data.to_vec())
} }
/// Deserialize a Module from a slice. /// Deserialize a Module from a slice.
@@ -98,7 +97,7 @@ impl SerializableModule {
pub fn deserialize_from_archive( pub fn deserialize_from_archive(
archived: &ArchivedSerializableModule, archived: &ArchivedSerializableModule,
) -> Result<Self, DeserializeError> { ) -> Result<Self, DeserializeError> {
let mut deserializer = SharedDeserializerAdapter::new(AllocDeserializer); let mut deserializer = SharedDeserializeMap::new();
RkyvDeserialize::deserialize(archived, &mut deserializer) RkyvDeserialize::deserialize(archived, &mut deserializer)
.map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e))) .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
} }

View File

@@ -25,6 +25,7 @@ serde = { version = "1.0", features = ["derive", "rc"] }
serde_bytes = { version = "0.11" } serde_bytes = { version = "0.11" }
lazy_static = "1.4" lazy_static = "1.4"
loupe = "0.1" loupe = "0.1"
enumset = "1.0"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -1,12 +1,13 @@
use crate::{ use crate::{
resolve_imports, InstantiationError, Resolver, RuntimeError, SerializeError, Tunables, resolve_imports, InstantiationError, Resolver, RuntimeError, SerializeError, Tunables,
}; };
use enumset::EnumSet;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::any::Any; use std::any::Any;
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::Features; use wasmer_compiler::{CpuFeature, Features};
use wasmer_types::entity::{BoxedSlice, PrimaryMap}; use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{ use wasmer_types::{
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo,
@@ -43,6 +44,9 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
/// Returns the features for this Artifact /// Returns the features for this Artifact
fn features(&self) -> &Features; 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`. /// Returns the memory styles associated with this `Artifact`.
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>; fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>;
@@ -96,6 +100,16 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
resolver: &dyn Resolver, resolver: &dyn Resolver,
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
) -> Result<InstanceHandle, InstantiationError> { ) -> 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()?; self.preinstantiate()?;
let module = self.module(); let module = self.module();

View File

@@ -91,6 +91,11 @@ pub enum InstantiationError {
#[error(transparent)] #[error(transparent)]
Link(LinkError), 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 /// A runtime error occured while invoking the start function
#[error(transparent)] #[error(transparent)]
Start(RuntimeError), Start(RuntimeError),

View File

@@ -14,7 +14,7 @@ edition = "2018"
serde = { version = "1.0", features = ["derive", "rc"], optional = true, default-features = false } serde = { version = "1.0", features = ["derive", "rc"], optional = true, default-features = false }
thiserror = "1.0" thiserror = "1.0"
indexmap = { version = "1.6", features = ["serde-1"] } 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"] } loupe = { version = "0.1", features = ["enable-indexmap"] }
[features] [features]

View File

@@ -3,32 +3,31 @@ use core::hash::Hash;
use indexmap::IndexMap; use indexmap::IndexMap;
use rkyv::{Archive, Deserialize, Serialize}; use rkyv::{Archive, Deserialize, Serialize};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::{collections::HashMap, hash::Hash}; use std::hash::Hash;
#[derive(Serialize, Deserialize, Archive)] #[derive(Serialize, Deserialize, Archive)]
/// Rkyv Archivable IndexMap /// Rkyv Archivable IndexMap
pub struct ArchivableIndexMap<K: Hash + Eq + Archive, V: Archive> { pub struct ArchivableIndexMap<K: Hash + Ord + Archive, V: Archive> {
indices: HashMap<K, u64>,
entries: Vec<(K, V)>, 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> { fn from(it: IndexMap<K, V>) -> ArchivableIndexMap<K, V> {
let mut r = ArchivableIndexMap { let mut r = ArchivableIndexMap {
indices: HashMap::new(),
entries: Vec::new(), entries: Vec::new(),
}; };
let mut i: u64 = 0;
for (k, v) in it.into_iter() { for (k, v) in it.into_iter() {
r.indices.insert(k.clone(), i);
r.entries.push((k, v)); r.entries.push((k, v));
i += 1;
} }
r 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> { fn into(self) -> IndexMap<K, V> {
let mut r = IndexMap::new(); let mut r = IndexMap::new();
for (k, v) in self.entries.into_iter() { for (k, v) in self.entries.into_iter() {

View File

@@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct LocalFunctionIndex(u32);
entity_impl!(LocalFunctionIndex); entity_impl!(LocalFunctionIndex);
@@ -44,7 +44,7 @@ entity_impl!(LocalMemoryIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct LocalGlobalIndex(u32);
entity_impl!(LocalGlobalIndex); entity_impl!(LocalGlobalIndex);
@@ -60,7 +60,7 @@ entity_impl!(ArchivedLocalGlobalIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct FunctionIndex(u32);
entity_impl!(FunctionIndex); entity_impl!(FunctionIndex);
@@ -76,7 +76,7 @@ entity_impl!(ArchivedFunctionIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct TableIndex(u32);
entity_impl!(TableIndex); entity_impl!(TableIndex);
@@ -92,7 +92,7 @@ entity_impl!(ArchivedTableIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct GlobalIndex(u32);
entity_impl!(GlobalIndex); entity_impl!(GlobalIndex);
@@ -108,7 +108,7 @@ entity_impl!(ArchivedGlobalIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct MemoryIndex(u32);
entity_impl!(MemoryIndex); entity_impl!(MemoryIndex);
@@ -124,7 +124,7 @@ entity_impl!(ArchivedMemoryIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct SignatureIndex(u32);
entity_impl!(SignatureIndex); entity_impl!(SignatureIndex);
@@ -140,7 +140,7 @@ entity_impl!(ArchivedSignatureIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct DataIndex(u32);
entity_impl!(DataIndex); entity_impl!(DataIndex);
@@ -156,7 +156,7 @@ entity_impl!(ArchivedDataIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct ElemIndex(u32);
entity_impl!(ElemIndex); entity_impl!(ElemIndex);
@@ -172,7 +172,7 @@ entity_impl!(ArchivedElemIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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); pub struct CustomSectionIndex(u32);
entity_impl!(CustomSectionIndex); entity_impl!(CustomSectionIndex);
@@ -188,7 +188,7 @@ entity_impl!(ArchivedCustomSectionIndex);
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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 { pub enum ExportIndex {
/// Function export. /// Function export.
@@ -210,7 +210,7 @@ pub enum ExportIndex {
)] )]
#[cfg_attr( #[cfg_attr(
feature = "enable-rkyv", 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 { pub enum ImportIndex {
/// Function import. /// Function import.

View File

@@ -17,16 +17,17 @@ use indexmap::IndexMap;
use loupe::MemoryUsage; use loupe::MemoryUsage;
#[cfg(feature = "enable-rkyv")] #[cfg(feature = "enable-rkyv")]
use rkyv::{ use rkyv::{
de::SharedDeserializer, ser::Serializer, ser::SharedSerializer, Archive, Archived, de::SharedDeserializeRegistry, ser::ScratchSpace, ser::Serializer,
Deserialize as RkyvDeserialize, Fallible, Serialize as RkyvSerialize, ser::SharedSerializeRegistry, Archive, Archived, Deserialize as RkyvDeserialize, Fallible,
Serialize as RkyvSerialize,
}; };
#[cfg(feature = "enable-serde")] #[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "enable-rkyv")]
use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::iter::ExactSizeIterator; use std::iter::ExactSizeIterator;
#[cfg(feature = "enable-rkyv")]
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use std::sync::Arc; use std::sync::Arc;
@@ -142,10 +143,10 @@ pub struct ArchivableModuleInfo {
exports: ArchivableIndexMap<String, ExportIndex>, exports: ArchivableIndexMap<String, ExportIndex>,
start_function: Option<FunctionIndex>, start_function: Option<FunctionIndex>,
table_initializers: Vec<TableInitializer>, table_initializers: Vec<TableInitializer>,
passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>, passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
passive_data: HashMap<DataIndex, Arc<[u8]>>, passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>, global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
function_names: HashMap<FunctionIndex, String>, function_names: BTreeMap<FunctionIndex, String>,
signatures: PrimaryMap<SignatureIndex, FunctionType>, signatures: PrimaryMap<SignatureIndex, FunctionType>,
functions: PrimaryMap<FunctionIndex, SignatureIndex>, functions: PrimaryMap<FunctionIndex, SignatureIndex>,
tables: PrimaryMap<TableIndex, TableType>, tables: PrimaryMap<TableIndex, TableType>,
@@ -168,10 +169,10 @@ impl From<ModuleInfo> for ArchivableModuleInfo {
exports: ArchivableIndexMap::from(it.exports), exports: ArchivableIndexMap::from(it.exports),
start_function: it.start_function, start_function: it.start_function,
table_initializers: it.table_initializers, table_initializers: it.table_initializers,
passive_elements: it.passive_elements, passive_elements: it.passive_elements.into_iter().collect(),
passive_data: it.passive_data, passive_data: it.passive_data.into_iter().collect(),
global_initializers: it.global_initializers, global_initializers: it.global_initializers,
function_names: it.function_names, function_names: it.function_names.into_iter().collect(),
signatures: it.signatures, signatures: it.signatures,
functions: it.functions, functions: it.functions,
tables: it.tables, tables: it.tables,
@@ -197,10 +198,10 @@ impl From<ArchivableModuleInfo> for ModuleInfo {
exports: it.exports.into(), exports: it.exports.into(),
start_function: it.start_function, start_function: it.start_function,
table_initializers: it.table_initializers, table_initializers: it.table_initializers,
passive_elements: it.passive_elements, passive_elements: it.passive_elements.into_iter().collect(),
passive_data: it.passive_data, passive_data: it.passive_data.into_iter().collect(),
global_initializers: it.global_initializers, global_initializers: it.global_initializers,
function_names: it.function_names, function_names: it.function_names.into_iter().collect(),
signatures: it.signatures, signatures: it.signatures,
functions: it.functions, functions: it.functions,
tables: it.tables, tables: it.tables,
@@ -228,20 +229,22 @@ impl Archive for ModuleInfo {
type Archived = <ArchivableModuleInfo as Archive>::Archived; type Archived = <ArchivableModuleInfo as Archive>::Archived;
type Resolver = <ArchivableModuleInfo as Archive>::Resolver; 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) ArchivableModuleInfo::from(self).resolve(pos, resolver, out)
} }
} }
#[cfg(feature = "enable-rkyv")] #[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> { fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
ArchivableModuleInfo::from(self).serialize(serializer) ArchivableModuleInfo::from(self).serialize(serializer)
} }
} }
#[cfg(feature = "enable-rkyv")] #[cfg(feature = "enable-rkyv")]
impl<D: Fallible + ?Sized + SharedDeserializer> RkyvDeserialize<ModuleInfo, D> impl<D: Fallible + ?Sized + SharedDeserializeRegistry> RkyvDeserialize<ModuleInfo, D>
for Archived<ModuleInfo> for Archived<ModuleInfo>
{ {
fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> { fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {

View File

@@ -21,7 +21,7 @@ more-asserts = "0.2"
cfg-if = "1.0" cfg-if = "1.0"
backtrace = "0.3" backtrace = "0.3"
serde = { version = "1.0", features = ["derive", "rc"] } 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"] } loupe = { version = "0.1", features = ["enable-indexmap"] }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]

View File

@@ -99,13 +99,16 @@ cfg_if::cfg_if! {
unsafe fn thread_stack() -> (usize, usize) { unsafe fn thread_stack() -> (usize, usize) {
let this_thread = libc::pthread_self(); let this_thread = libc::pthread_self();
let mut thread_attrs: libc::pthread_attr_t = mem::zeroed(); 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 stackaddr: *mut libc::c_void = ptr::null_mut();
let mut stacksize: libc::size_t = 0; let mut stacksize: libc::size_t = 0;
libc::pthread_attr_getstack(&thread_attrs, &mut stackaddr, &mut stacksize); #[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) (stackaddr as usize, stacksize)
} }

View File

@@ -1 +1 @@
1.53 1.56

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

View File

@@ -6,6 +6,7 @@
extern crate compiler_test_derive; extern crate compiler_test_derive;
mod config; mod config;
mod deterministic;
mod imports; mod imports;
mod issues; mod issues;
mod metering; mod metering;

View File

@@ -257,7 +257,9 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> {
.err() .err()
.unwrap(); .unwrap();
match err { match err {
InstantiationError::Link(_) | InstantiationError::HostEnvInitialization(_) => { InstantiationError::Link(_)
| InstantiationError::HostEnvInitialization(_)
| InstantiationError::CpuFeature(_) => {
panic!("It should be a start error") panic!("It should be a start error")
} }
InstantiationError::Start(err) => { InstantiationError::Start(err) => {

View File

@@ -70,7 +70,7 @@ cranelift spec::simd::simd_i8x16_arith2
cranelift spec::simd::simd_int_to_int_extend cranelift spec::simd::simd_int_to_int_extend
# Windows doesn't overcommit and fails to allocate 4GB of memory # 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 # Frontends

View File

@@ -16,19 +16,14 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true }
serde_bytes = { version = "0.11", optional = true } serde_bytes = { version = "0.11", optional = true }
bincode = { version = "1.2", optional = true } bincode = { version = "1.2", optional = true }
loupe = "0.1" loupe = "0.1"
enumset = "1.0"
[features] [features]
# Enable the `compiler` feature if you want the engine to compile # Enable the `compiler` feature if you want the engine to compile
# and not be only on headless mode. # and not be only on headless mode.
default = ["serialize", "compiler"] default = ["serialize", "compiler"]
compiler = [ compiler = ["wasmer-compiler/translator"]
"wasmer-compiler/translator" serialize = ["serde", "serde_bytes", "bincode"]
]
serialize = [
"serde",
"serde_bytes",
"bincode"
]
[badges] [badges]
# TODO: publish this crate again and deprecate it # TODO: publish this crate again and deprecate it

View File

@@ -2,13 +2,14 @@
//! done as separate steps. //! done as separate steps.
use crate::engine::DummyEngine; use crate::engine::DummyEngine;
use enumset::EnumSet;
use loupe::MemoryUsage; use loupe::MemoryUsage;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::CompileError;
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
use wasmer_compiler::ModuleEnvironment; use wasmer_compiler::ModuleEnvironment;
use wasmer_compiler::{CompileError, CpuFeature};
use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError, Tunables}; use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError, Tunables};
use wasmer_types::entity::{BoxedSlice, PrimaryMap}; use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{ use wasmer_types::{
@@ -30,6 +31,7 @@ pub struct DummyArtifactMetadata {
// Plans for that module // Plans for that module
pub memory_styles: PrimaryMap<MemoryIndex, MemoryStyle>, pub memory_styles: PrimaryMap<MemoryIndex, MemoryStyle>,
pub table_styles: PrimaryMap<TableIndex, TableStyle>, pub table_styles: PrimaryMap<TableIndex, TableStyle>,
pub cpu_features: u64,
} }
/// A Dummy artifact. /// A Dummy artifact.
@@ -104,6 +106,7 @@ impl DummyArtifact {
data_initializers, data_initializers,
memory_styles, memory_styles,
table_styles, table_styles,
cpu_features: engine.target().cpu_features().as_u64(),
}; };
Self::from_parts(&engine, metadata) Self::from_parts(&engine, metadata)
} }
@@ -211,6 +214,10 @@ impl Artifact for DummyArtifact {
&self.metadata.features &self.metadata.features
} }
fn cpu_features(&self) -> EnumSet<CpuFeature> {
EnumSet::from_u64(self.metadata.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] { fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.metadata.data_initializers &*self.metadata.data_initializers
} }