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 = [
# Put the VM functions in the dynamic symbol table.
"-C", "link-arg=-Wl,-E",

View File

@@ -22,14 +22,14 @@ jobs:
- name: Install LLVM
shell: bash
run: |
curl --proto '=https' --tlsv1.2 -sSf ${{ env.LLVM_URL }} -L -o llvm.tar.gz
curl --proto '=https' --tlsv1.2 -sSf ${{ env.LLVM_URL }} -L -o llvm.tar.xz
mkdir ${{ env.LLVM_DIR }}
tar xf llvm.tar.gz --strip-components=1 -C ${{ env.LLVM_DIR }}
tar xf llvm.tar.xz --strip-components=1 -C ${{ env.LLVM_DIR }}
echo "${{ env.LLVM_DIR }}/bin" >> $GITHUB_PATH
echo "LLVM_SYS_110_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV
echo "LLVM_SYS_120_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV
env:
LLVM_DIR: ${{ github.workspace }}/llvm-11
LLVM_URL: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz'
LLVM_DIR: ${{ github.workspace }}/llvm-13
LLVM_URL: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz'
- name: Build & package documentation
run: make package-docs
- name: Publish documentation

View File

@@ -23,11 +23,11 @@ jobs:
components: rustfmt, clippy
- name: Install LLVM (Linux)
run: |
curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/11.x/linux-amd64.tar.gz -L -o /opt/llvm.tar.gz
mkdir -p /opt/llvm-11
tar xf /opt/llvm.tar.gz --strip-components=1 -C /opt/llvm-11
echo '/opt/llvm-11/bin' >> $GITHUB_PATH
echo 'LLVM_SYS_110_PREFIX=/opt/llvm-11' >> $GITHUB_ENV
curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz -L -o /opt/llvm.tar.xz
mkdir -p /opt/llvm-12
tar xf /opt/llvm.tar.xz --strip-components=1 -C /opt/llvm-12
echo '/opt/llvm-12/bin' >> $GITHUB_PATH
echo 'LLVM_SYS_120_PREFIX=/opt/llvm-12' >> $GITHUB_ENV
- run: make lint
env:
ENABLE_CRANELIFT: "1"

View File

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

54
Cargo.lock generated
View File

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

View File

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

View File

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

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]
fn test_into_array() {
assert_eq!(().into_array(), []);
assert_eq!(().into_array(), [0i128; 0]);
assert_eq!((1).into_array(), [1]);
assert_eq!((1i32, 2i64).into_array(), [1, 2]);
assert_eq!(

View File

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

View File

@@ -58,6 +58,11 @@ pub enum InstantiationError {
#[error(transparent)]
Start(RuntimeError),
/// The module was compiled with a CPU feature that is not available on
/// the current host.
#[error("missing requires CPU features: {0:?}")]
CpuFeature(String),
/// Error occurred when initializing the host environment.
#[error(transparent)]
HostEnvInitialization(HostEnvInitError),
@@ -68,6 +73,7 @@ impl From<wasmer_engine::InstantiationError> for InstantiationError {
match other {
wasmer_engine::InstantiationError::Link(e) => Self::Link(e),
wasmer_engine::InstantiationError::Start(e) => Self::Start(e),
wasmer_engine::InstantiationError::CpuFeature(e) => Self::CpuFeature(e),
}
}
}

View File

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

View File

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

View File

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

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_t wasm_bytes;
wat2wasm(&wat, &wasm_bytes);
wasm_byte_vec_delete(&wat);
printf("Creating the store...\n");
wasm_engine_t* engine = wasm_engine_new();

View File

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

View File

@@ -49,13 +49,12 @@
use libc::{c_char, c_int};
use std::cell::RefCell;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::fmt::Display;
use std::ptr::{self, NonNull};
use std::slice;
thread_local! {
static LAST_ERROR: RefCell<Option<Box<dyn Error>>> = RefCell::new(None);
static LAST_ERROR: RefCell<Option<String>> = RefCell::new(None);
}
/// Rust function to register a new error.
@@ -63,24 +62,23 @@ thread_local! {
/// # Example
///
/// ```rust,no_run
/// # use wasmer::error::{update_last_error, CApiError};
/// # use wasmer::error::update_last_error;
///
/// update_last_error(CApiError {
/// msg: "Hello, World!".to_string(),
/// });
/// update_last_error("Hello, World!");
/// ```
pub fn update_last_error<E: Error + 'static>(err: E) {
pub fn update_last_error<E: Display>(err: E) {
LAST_ERROR.with(|prev| {
*prev.borrow_mut() = Some(Box::new(err));
*prev.borrow_mut() = Some(err.to_string());
});
}
/// Retrieve the most recent error, clearing it in the process.
pub(crate) fn take_last_error() -> Option<Box<dyn Error>> {
pub(crate) fn take_last_error() -> Option<String> {
LAST_ERROR.with(|prev| prev.borrow_mut().take())
}
/// Gets the length in bytes of the last error if any, zero otherwise.
/// Gets the length in bytes of the last error if any, zero otherwise. This
/// includes th NUL terminator byte.
///
/// This can be used to dynamically allocate a buffer with the correct number of
/// bytes needed to store a message.
@@ -88,10 +86,11 @@ pub(crate) fn take_last_error() -> Option<Box<dyn Error>> {
/// # Example
///
/// See this module's documentation to get a complete example.
// TODO(Amanieu): This should use size_t
#[no_mangle]
pub extern "C" fn wasmer_last_error_length() -> c_int {
LAST_ERROR.with(|prev| match *prev.borrow() {
Some(ref err) => err.to_string().len() as c_int + 1,
Some(ref err) => err.len() as c_int + 1,
None => 0,
})
}
@@ -118,6 +117,7 @@ pub extern "C" fn wasmer_last_error_length() -> c_int {
/// # Example
///
/// See this module's documentation to get a complete example.
// TODO(Amanieu): This should use size_t
#[no_mangle]
pub unsafe extern "C" fn wasmer_last_error_message(
buffer: Option<NonNull<c_char>>,
@@ -156,18 +156,3 @@ pub unsafe extern "C" fn wasmer_last_error_message(
error_message.len() as c_int + 1
}
/// Rust type to represent a C API error.
#[derive(Debug)]
pub struct CApiError {
/// The error message.
pub msg: String,
}
impl Display for CApiError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", &self.msg)
}
}
impl Error for CApiError {}

View File

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

View File

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

View File

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

View File

@@ -48,7 +48,6 @@ pub unsafe extern "C" fn wasm_global_new(
#[no_mangle]
pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>) {}
// TODO: figure out if these should be deep or shallow copies
#[no_mangle]
pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> {
// do shallow copy

View File

@@ -38,7 +38,6 @@ pub unsafe extern "C" fn wasm_memory_new(
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_delete(_memory: Option<Box<wasm_memory_t>>) {}
// TODO: figure out if these should be deep or shallow copies
#[no_mangle]
pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box<wasm_memory_t> {
// do shallow copy

View File

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

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

View File

@@ -1,13 +1,121 @@
#[doc(hidden)]
#[macro_export]
macro_rules! wasm_declare_vec_inner {
($name:ident) => {
wasm_declare_vec_inner!($name, wasm);
};
(
name: $name:ident,
ty: $elem_ty:ty,
c_ty: $c_ty:expr,
c_val: $c_val:expr,
new: $new:ident,
empty: $empty:ident,
uninit: $uninit:ident,
copy: $copy:ident,
delete: $delete:ident,
) => {
#[doc = concat!("Represents a vector of `", $c_ty, "`.
($name:ident, $prefix:ident) => {
paste::paste! {
#[doc = "Creates an empty vector of [`" $prefix "_" $name "_t`].
Read the documentation of [`", $c_ty, "`] to see more concrete examples.
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer.h\"
#
void example(", $c_ty, " x, ", $c_ty, " y) {
// Create a vector of 2 `", $c_ty, "`.
", $c_ty, " items[2] = {x, y};
", stringify!($name), " vector;
", stringify!($new), "(&vector, 2, items);
// Check that it contains 2 items.
assert(vector.size == 2);
// Free it.
", stringify!($delete), "(&vector);
}
#
# int main() { example(", $c_val, ", ", $c_val, "); return 0; }
# })
# .success();
# }
```")]
#[repr(C)]
pub struct $name {
pub size: usize,
pub data: *mut $elem_ty,
}
impl $name {
// Note that this does not free any existing buffer.
pub fn set_buffer(&mut self, buffer: Vec<$elem_ty>) {
let mut vec = buffer.into_boxed_slice();
self.size = vec.len();
self.data = vec.as_mut_ptr();
std::mem::forget(vec);
}
pub fn as_slice(&self) -> &[$elem_ty] {
// Note that we're careful to not create a slice with a null
// pointer as the data pointer, since that isn't defined
// behavior in Rust.
if self.size == 0 {
&[]
} else {
assert!(!self.data.is_null());
unsafe { std::slice::from_raw_parts(self.data, self.size) }
}
}
pub fn as_uninit_slice(&mut self) -> &mut [std::mem::MaybeUninit<$elem_ty>] {
// Note that we're careful to not create a slice with a null
// pointer as the data pointer, since that isn't defined
// behavior in Rust.
if self.size == 0 {
&mut []
} else {
assert!(!self.data.is_null());
unsafe { std::slice::from_raw_parts_mut(self.data as _, self.size) }
}
}
pub fn take(&mut self) -> Vec<$elem_ty> {
if self.data.is_null() {
return Vec::new();
}
let vec = unsafe { Vec::from_raw_parts(self.data, self.size, self.size) };
self.data = std::ptr::null_mut();
self.size = 0;
return vec;
}
}
impl From<Vec<$elem_ty>> for $name {
fn from(vec: Vec<$elem_ty>) -> Self {
let mut vec = vec.into_boxed_slice();
let result = $name {
size: vec.len(),
data: vec.as_mut_ptr(),
};
std::mem::forget(vec);
result
}
}
impl Clone for $name {
fn clone(&self) -> Self {
self.as_slice().to_vec().into()
}
}
impl Drop for $name {
fn drop(&mut self) {
drop(self.take());
}
}
#[doc = concat!("Creates an empty vector of [`", $c_ty, "`].
# Example
@@ -18,31 +126,89 @@ macro_rules! wasm_declare_vec_inner {
# #include \"tests/wasmer.h\"
#
int main() {
// Creates an empty vector of `" $prefix "_" $name "_t`.
" $prefix "_" $name "_vec_t vector;
" $prefix "_" $name "_vec_new_empty(&vector);
// Creates an empty vector of `", $c_ty, "`.
", stringify!($name), " vector;
", stringify!($empty), "(&vector);
// Check that it is empty.
assert(vector.size == 0);
// Free it.
" $prefix "_" $name "_vec_delete(&vector);
", stringify!($delete), "(&vector);
return 0;
}
# })
# .success();
# }
```"]
#[no_mangle]
pub unsafe extern "C" fn [<$prefix _ $name _vec_new_empty>](out: *mut [<$prefix _ $name _vec_t>]) {
// TODO: actually implement this
[<$prefix _ $name _vec_new_uninitialized>](out, 0);
}
```")]
#[no_mangle]
pub extern "C" fn $empty(out: &mut $name) {
out.size = 0;
out.data = std::ptr::null_mut();
}
}
#[doc = concat!("Creates a new uninitialized vector of [`", $c_ty, "`].
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer.h\"
#
int main() {
// Creates an empty vector of `", $c_ty, "`.
", stringify!($name), " vector;
", stringify!($uninit), "(&vector, 3);
// Check that it contains 3 items.
assert(vector.size == 3);
// Free it.
", stringify!($delete), "(&vector);
return 0;
}
# })
# .success();
# }
```")]
#[no_mangle]
pub extern "C" fn $uninit(out: &mut $name, size: usize) {
out.set_buffer(vec![Default::default(); size]);
}
#[doc = concat!("Creates a new vector of [`", $c_ty, "`].
# Example
See the [`", stringify!($name), "`] type to get an example.")]
#[no_mangle]
pub unsafe extern "C" fn $new(out: &mut $name, size: usize, ptr: *const $elem_ty) {
let vec = (0..size).map(|i| ptr.add(i).read()).collect();
out.set_buffer(vec);
}
#[doc = concat!("Performs a deep copy of a vector of [`", $c_ty, "`].")]
#[no_mangle]
pub extern "C" fn $copy(out: &mut $name, src: &$name) {
out.set_buffer(src.as_slice().to_vec());
}
#[doc = concat!("Deletes a vector of [`", $c_ty, "`].
# Example
See the [`", stringify!($name), "`] type to get an example.")]
#[no_mangle]
pub extern "C" fn $delete(out: &mut $name) {
out.take();
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! wasm_declare_vec {
($name:ident) => {
wasm_declare_vec!($name, wasm);
@@ -50,218 +216,25 @@ macro_rules! wasm_declare_vec {
($name:ident, $prefix:ident) => {
paste::paste! {
#[doc = "Represents a vector of `" $prefix "_" $name "_t`.
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples.
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer.h\"
#
int main() {
// Create a vector of 2 `" $prefix "_" $name "_t`.
" $prefix "_" $name "_t x;
" $prefix "_" $name "_t y;
" $prefix "_" $name "_t* items[2] = {&x, &y};
" $prefix "_" $name "_vec_t vector;
" $prefix "_" $name "_vec_new(&vector, 2, (" $prefix "_" $name "_t*) items);
// Check that it contains 2 items.
assert(vector.size == 2);
// Free it.
" $prefix "_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[derive(Debug)]
#[repr(C)]
pub struct [<$prefix _ $name _vec_t>] {
pub size: usize,
pub data: *mut [<$prefix _ $name _t>],
}
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 _ $name _vec_t>],
ty: [<$prefix _ $name _t>],
c_ty: stringify!([<$prefix _ $name _t>]),
c_val: concat!("({ ",
stringify!([<$prefix _ $name _t>]), " foo;\n",
"memset(&foo, 0, sizeof(foo));\n",
"foo;\n",
"})"),
new: [<$prefix _ $name _vec_new>],
empty: [<$prefix _ $name _vec_new_empty>],
uninit: [<$prefix _ $name _vec_new_uninitialized>],
copy: [<$prefix _ $name _vec_copy>],
delete: [<$prefix _ $name _vec_delete>],
);
}
wasm_declare_vec_inner!($name, $prefix);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! wasm_declare_boxed_vec {
($name:ident) => {
wasm_declare_boxed_vec!($name, wasm);
@@ -269,223 +242,60 @@ macro_rules! wasm_declare_boxed_vec {
($name:ident, $prefix:ident) => {
paste::paste! {
#[doc = "Represents a vector of `" $prefix "_" $name "_t`.
Read the documentation of [`" $prefix "_" $name "_t`] to see more concrete examples."]
#[derive(Debug)]
#[repr(C)]
pub struct [<$prefix _ $name _vec_t>] {
pub size: usize,
pub data: *mut *mut [<$prefix _ $name _t>],
}
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...
wasm_declare_vec_inner!(
name: [<$prefix _ $name _vec_t>],
ty: Option<Box<[<$prefix _ $name _t>]>>,
c_ty: stringify!([<$prefix _ $name _t>] *),
c_val: "NULL",
new: [<$prefix _ $name _vec_new>],
empty: [<$prefix _ $name _vec_new_empty>],
uninit: [<$prefix _ $name _vec_new_uninitialized>],
copy: [<$prefix _ $name _vec_copy>],
delete: [<$prefix _ $name _vec_delete>],
);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! wasm_declare_own {
macro_rules! wasm_impl_copy {
($name:ident) => {
wasm_declare_own!($name, $prefix);
wasm_impl_copy!($name, wasm);
};
($name:ident, $prefix:ident) => {
paste::paste! {
#[repr(C)]
pub struct [<$prefix _ $name _t>] {}
#[no_mangle]
pub extern "C" fn [<$prefix _ $name _delete>](_arg: *mut [<$prefix _ $name _t>]) {
todo!("in generated delete")
pub extern "C" fn [<$prefix _ $name _copy>](src: Option<&[<$prefix _ $name _t>]>) -> Option<Box<[<$prefix _ $name _t>]>> {
Some(Box::new(src?.clone()))
}
}
};
}
#[macro_export]
macro_rules! wasm_impl_delete {
($name:ident) => {
wasm_impl_delete!($name, wasm);
};
($name:ident, $prefix:ident) => {
paste::paste! {
#[no_mangle]
pub extern "C" fn [<$prefix _ $name _delete>](_: Option<Box<[<$prefix _ $name _t>]>>) {}
}
};
}
macro_rules! wasm_impl_copy_delete {
($name:ident) => {
wasm_impl_copy_delete!($name, wasm);
};
($name:ident, $prefix:ident) => {
wasm_impl_copy!($name, $prefix);
wasm_impl_delete!($name, $prefix);
};
}
macro_rules! c_try {
($expr:expr; otherwise $return:expr) => {{
let res: Result<_, _> = $expr;

View File

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

View File

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

View File

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

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

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

@@ -54,7 +54,6 @@
//! ```
use super::super::types::wasm_name_t;
use crate::error::CApiError;
use enumset::EnumSet;
use std::slice;
use std::str::{self, FromStr};
@@ -153,7 +152,7 @@ pub unsafe extern "C" fn wasmer_triple_new(
)));
Some(Box::new(wasmer_triple_t {
inner: c_try!(Triple::from_str(triple).map_err(|e| CApiError { msg: e.to_string() })),
inner: c_try!(Triple::from_str(triple)),
}))
}

View File

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

View File

@@ -1,5 +1,5 @@
use super::types::{wasm_ref_t, wasm_valkind_enum};
use crate::error::{update_last_error, CApiError};
use crate::error::update_last_error;
use std::convert::{TryFrom, TryInto};
use wasmer_api::Val;
@@ -121,6 +121,15 @@ impl Clone for wasm_val_t {
}
}
impl Default for wasm_val_t {
fn default() -> Self {
Self {
kind: wasm_valkind_enum::WASM_I64 as _,
of: wasm_val_inner { int64_t: 0 },
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_val_copy(
// own
@@ -147,7 +156,7 @@ pub unsafe extern "C" fn wasm_val_copy(
},
Err(e) => {
update_last_error(CApiError { msg: e.to_string() });
update_last_error(e);
return;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,14 +24,14 @@ to native speeds.
## Requirements
The LLVM compiler requires a valid installation of LLVM in your system.
It currently requires **LLVM 11**.
It currently requires **LLVM 12**.
You can install LLVM easily on your Debian-like system via this command:
```bash
wget https://apt.llvm.org/llvm.sh -O /tmp/llvm.sh
sudo bash /tmp/llvm.sh 11
sudo bash /tmp/llvm.sh 12
```
Or in macOS:

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,9 +4,7 @@
use crate::compiler::SinglepassCompiler;
use loupe::MemoryUsage;
use std::sync::Arc;
use wasmer_compiler::{
CallingConvention, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target,
};
use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target};
use wasmer_types::Features;
#[derive(Debug, Clone, MemoryUsage)]
@@ -15,8 +13,6 @@ pub struct Singlepass {
pub(crate) enable_stack_check: bool,
/// The middleware chain.
pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
#[loupe(skip)]
pub(crate) calling_convention: CallingConvention,
}
impl Singlepass {
@@ -27,12 +23,6 @@ impl Singlepass {
enable_nan_canonicalization: true,
enable_stack_check: false,
middlewares: vec![],
calling_convention: match Target::default().triple().default_calling_convention() {
Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall,
Ok(CallingConvention::SystemV) => CallingConvention::SystemV,
//Ok(CallingConvention::AppleAarch64) => AppleAarch64,
_ => panic!("Unsupported Calling convention for Singlepass"),
},
}
}

View File

@@ -1,6 +1,10 @@
pub use crate::x64_decl::{GPR, XMM};
use dynasm::dynasm;
use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi};
use dynasmrt::{
x64::X64Relocation, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, VecAssembler,
};
type Assembler = VecAssembler<X64Relocation>;
/// Force `dynasm!` to use the correct arch (x64) when cross-compiling.
/// `dynasm!` proc-macro tries to auto-detect it by default by looking at the
@@ -479,7 +483,7 @@ macro_rules! binop_shift {
macro_rules! jmp_op {
($ins:ident, $assembler:tt, $label:ident) => {
dynasm!($assembler ; $ins =>$label);
dynasm!($assembler ; $ins =>$label)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -91,6 +91,11 @@ pub enum InstantiationError {
#[error(transparent)]
Link(LinkError),
/// The module was compiled with a CPU feature that is not available on
/// the current host.
#[error("module compiled with CPU feature that is missing from host")]
CpuFeature(String),
/// A runtime error occured while invoking the start function
#[error(transparent)]
Start(RuntimeError),

View File

@@ -14,7 +14,7 @@ edition = "2018"
serde = { version = "1.0", features = ["derive", "rc"], optional = true, default-features = false }
thiserror = "1.0"
indexmap = { version = "1.6", features = ["serde-1"] }
rkyv = { version = "0.6.1", optional = true }
rkyv = { version = "0.7.20", optional = true }
loupe = { version = "0.1", features = ["enable-indexmap"] }
[features]

View File

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

View File

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

View File

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

View File

@@ -21,7 +21,7 @@ more-asserts = "0.2"
cfg-if = "1.0"
backtrace = "0.3"
serde = { version = "1.0", features = ["derive", "rc"] }
rkyv = { version = "0.6.1", optional = true}
rkyv = { version = "0.7.20", optional = true }
loupe = { version = "0.1", features = ["enable-indexmap"] }
[target.'cfg(target_os = "windows")'.dependencies]

View File

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

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;
mod config;
mod deterministic;
mod imports;
mod issues;
mod metering;

View File

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

View File

@@ -70,7 +70,7 @@ cranelift spec::simd::simd_i8x16_arith2
cranelift spec::simd::simd_int_to_int_extend
# Windows doesn't overcommit and fails to allocate 4GB of memory
windows wast::wasmer::max_size_of_memory
windows wasmer::max_size_of_memory
# Frontends

View File

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

View File

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