Merge pull request #5443 from wasmerio/run-500-enable-c_api-backends-to-be-used-in-wasmers-implementation

Enable multiple backends supported by the api crate to be used in the c-api as well
This commit is contained in:
edoardo
2025-03-12 11:31:07 +01:00
committed by GitHub
34 changed files with 1272 additions and 795 deletions

View File

@@ -493,6 +493,11 @@ jobs:
build-cmd: "make build-capi && make build-capi-headless && make package-capi && make tar-capi", build-cmd: "make build-capi && make build-capi-headless && make package-capi && make tar-capi",
name: "Build and test C-API", name: "Build and test C-API",
}, },
{
key: capi-v8,
build-cmd: "make test-capi-v8",
name: "Build and test C-API with v8",
},
{ {
key: wasmer, key: wasmer,
build-cmd: "make build-wasmer && make package-wasmer && make tar-wasmer", build-cmd: "make build-wasmer && make package-wasmer && make tar-wasmer",
@@ -511,6 +516,10 @@ jobs:
target: x86_64-unknown-linux-gnu, target: x86_64-unknown-linux-gnu,
exe: "", exe: "",
llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz", llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz",
# Unfortunately, building a shared lib of the c_api with the v8
# backend does not work, due to unsupported relocations to hidden
# symbols in wee8.
supports_v8: false
}, },
{ {
build: macos-x64, build: macos-x64,
@@ -518,6 +527,7 @@ jobs:
target: x86_64-apple-darwin, target: x86_64-apple-darwin,
exe: "", exe: "",
llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-amd64.tar.xz", llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-amd64.tar.xz",
supports_v8: true
}, },
{ {
build: macos-arm, build: macos-arm,
@@ -525,6 +535,7 @@ jobs:
target: aarch64-apple-darwin, target: aarch64-apple-darwin,
exe: "", exe: "",
llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz", llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz",
supports_v8: true
}, },
{ {
build: windows-x64, build: windows-x64,
@@ -533,11 +544,13 @@ jobs:
exe: ".exe", exe: ".exe",
# For now, disable LLVM in `windows-x64.` # For now, disable LLVM in `windows-x64.`
# llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-windows-amd64.tar.xz' # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-windows-amd64.tar.xz'
supports_v8: false
}, },
{ {
build: windows-gnu, build: windows-gnu,
target: x86_64-pc-windows-gnu, target: x86_64-pc-windows-gnu,
os: ubuntu-22.04, os: ubuntu-22.04,
supports_v8: false
}, },
{ {
build: linux-musl, build: linux-musl,
@@ -545,6 +558,7 @@ jobs:
os: ubuntu-22.04, os: ubuntu-22.04,
exe: "", exe: "",
container: "alpine:latest", container: "alpine:latest",
supports_v8: false
}, },
] ]
container: ${{ matrix.metadata.container }} container: ${{ matrix.metadata.container }}
@@ -684,6 +698,10 @@ jobs:
TARGET: ${{ matrix.metadata.target }} TARGET: ${{ matrix.metadata.target }}
TARGET_DIR: target/${{ matrix.metadata.target }}/release TARGET_DIR: target/${{ matrix.metadata.target }}/release
CARGO_TARGET: ${{ matrix.metadata.target }} CARGO_TARGET: ${{ matrix.metadata.target }}
- name: Test C-API (v8)
shell: bash
run: ${{ matrix.build-what.build-cmd }}
if: ${{ matrix.build-what.key == 'capi-v8' && matrix.metadata.supports_v8 == true }}
- name: Build Wasmer - name: Build Wasmer
shell: bash shell: bash
if: ${{ matrix.build-what.key == 'wasmer' && matrix.metadata.build != 'windows-gnu' }} if: ${{ matrix.build-what.key == 'wasmer' && matrix.metadata.build != 'windows-gnu' }}

View File

@@ -559,7 +559,7 @@ build-docs-capi:
build-capi: build-capi:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,wasi,middlewares,webc_runner $(capi_compiler_features) --locked --no-default-features --features wat,sys-default,compiler,wasi,middlewares,webc_runner $(capi_compiler_features) --locked
build-capi-singlepass: build-capi-singlepass:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
@@ -585,9 +585,21 @@ build-capi-llvm-universal:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,llvm,wasi,middlewares,webc_runner --locked --no-default-features --features wat,compiler,llvm,wasi,middlewares,webc_runner --locked
build-capi-v8:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,v8-default,wasi --locked
build-capi-wamr:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,wamr-default,wasi --locked
build-capi-wasmi:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,wasmi-default,wasi --locked
build-capi-jsc: build-capi-jsc:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,jsc,wasi --locked --no-default-features --features wat,jsc-default,wasi --locked
# Headless (we include the minimal to be able to run) # Headless (we include the minimal to be able to run)
@@ -703,6 +715,10 @@ test-capi-ci: $(foreach compiler_engine,$(capi_compilers_engines),test-capi-crat
# compilers first # compilers first
test-capi: build-capi package-capi test-capi-ci test-capi: build-capi package-capi test-capi-ci
test-capi-v8: build-capi-v8 package-capi test-capi-integration-v8
test-capi-wasmi: build-capi-wasmi package-capi test-capi-integration-wasmi
test-capi-wamr: build-capi-wamr package-capi test-capi-integration-wamr
test-capi-jsc: build-capi-jsc package-capi test-capi-integration-jsc test-capi-jsc: build-capi-jsc package-capi test-capi-integration-jsc
test-capi-crate-%: test-capi-crate-%:

View File

@@ -161,6 +161,7 @@ js = ["wasm-bindgen", "js-sys"]
js-default = ["js", "std", "wasm-types-polyfill"] js-default = ["js", "std", "wasm-types-polyfill"]
wasm-types-polyfill = ["wasmparser"] wasm-types-polyfill = ["wasmparser"]
wat = ["dep:wat", "wasmparser"]
jsc = ["rusty_jsc", "wasm-types-polyfill", "wasmparser"] jsc = ["rusty_jsc", "wasm-types-polyfill", "wasmparser"]
jsc-default = ["jsc"] jsc-default = ["jsc"]

View File

@@ -1,8 +1,9 @@
#[cfg(feature = "wamr")] #[cfg(feature = "wamr")]
fn build_wamr() { fn build_wamr() {
use bindgen::callbacks::ParseCallbacks; use bindgen::callbacks::ParseCallbacks;
const WAMR_ZIP: &str = "https://github.com/bytecodealliance/wasm-micro-runtime/archive/0e4dffc47922bb6fcdcaed7de2a6edfe8c48a7cd.zip"; const WAMR_ZIP: &str =
const ZIP_NAME: &str = "wasm-micro-runtime-0e4dffc47922bb6fcdcaed7de2a6edfe8c48a7cd"; "https://github.com/bytecodealliance/wasm-micro-runtime/archive/refs/tags/WAMR-2.2.0.zip";
const ZIP_NAME: &str = "wasm-micro-runtime-WAMR-2.2.0";
use cmake::Config; use cmake::Config;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
@@ -36,24 +37,27 @@ fn build_wamr() {
// Cleanup tmp data from prior builds // Cleanup tmp data from prior builds
let wamr_dir = PathBuf::from(&crate_root).join("third_party/wamr"); let wamr_dir = PathBuf::from(&crate_root).join("third_party/wamr");
let zip_dir = PathBuf::from(&crate_root) if !wamr_dir.exists() {
.join("third_party") let zip_dir = PathBuf::from(&crate_root).join("third_party");
.join(ZIP_NAME); let _ = std::fs::remove_dir_all(&wamr_dir);
let _ = std::fs::remove_dir_all(&wamr_dir); let _ = std::fs::remove_dir_all(&zip_dir);
let _ = std::fs::remove_dir_all(&zip_dir);
// Fetch & extract wasm-micro-runtime source // Fetch & extract wasm-micro-runtime source
let zip = ureq::get(WAMR_ZIP).call().expect("failed to download wamr"); let zip = ureq::get(WAMR_ZIP).call().expect("failed to download wamr");
let mut zip_data = Vec::new(); let mut zip_data = Vec::new();
zip.into_reader() zip.into_reader()
.read_to_end(&mut zip_data) .read_to_end(&mut zip_data)
.expect("failed to download wamr"); .expect("failed to download wamr");
zip::read::ZipArchive::new(std::io::Cursor::new(zip_data)) zip::read::ZipArchive::new(std::io::Cursor::new(zip_data))
.expect("failed to open wamr zip file") .expect("failed to open wamr zip file")
.extract(&zip_dir) .extract(&zip_dir)
.expect("failed to extract wamr zip file"); .expect("failed to extract wamr zip file");
let _ = std::fs::remove_dir_all(&wamr_dir); let _ = std::fs::remove_dir_all(&wamr_dir);
std::fs::rename(zip_dir.join(ZIP_NAME), &wamr_dir).expect("failed to rename wamr dir"); std::fs::rename(zip_dir.join(ZIP_NAME), &wamr_dir)
.expect(&format!("failed to rename wamr dir: {zip_dir:?}"));
} else {
println!("cargo::rerun-if-changed={}", wamr_dir.display());
}
let wamr_platform_dir = wamr_dir.join("product-mini/platforms").join(target_os); let wamr_platform_dir = wamr_dir.join("product-mini/platforms").join(target_os);
let mut dst = Config::new(wamr_platform_dir.as_path()); let mut dst = Config::new(wamr_platform_dir.as_path());
@@ -83,7 +87,7 @@ fn build_wamr() {
.define("WAMR_BUILD_LIBC_WASI", "0") .define("WAMR_BUILD_LIBC_WASI", "0")
.define("WAMR_BUILD_LIBC_BUILTIN", "0") .define("WAMR_BUILD_LIBC_BUILTIN", "0")
.define("WAMR_BUILD_SHARED_MEMORY", "1") .define("WAMR_BUILD_SHARED_MEMORY", "1")
.define("WAMR_BUILD_MULTI_MODULE", "0") .define("WAMR_BUILD_MULTI_MODULE", "1")
.define("WAMR_DISABLE_HW_BOUND_CHECK", "1") .define("WAMR_DISABLE_HW_BOUND_CHECK", "1")
.define("WAMR_BUILD_TARGET", target_arch); .define("WAMR_BUILD_TARGET", target_arch);
@@ -216,7 +220,7 @@ fn build_wamr() {
"cargo:rustc-link-search=native={}", "cargo:rustc-link-search=native={}",
dst.join("build").display() dst.join("build").display()
); );
println!("cargo:rustc-link-lib=wamr"); println!("cargo:rustc-link-lib=static=wamr");
} }
#[cfg(feature = "v8")] #[cfg(feature = "v8")]
@@ -297,8 +301,17 @@ fn build_v8() {
} }
let header_path = v8_header_path.join("wasm.h"); let header_path = v8_header_path.join("wasm.h");
let mut args = vec![];
if cfg!(target_os = "macos") {
args.push("-I/usr/local/include");
args.push("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1");
args.push("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include");
args.push("-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include");
args.push("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks");
}
let bindings = bindgen::Builder::default() let bindings = bindgen::Builder::default()
.header(header_path.display().to_string()) .header(header_path.display().to_string())
.clang_args(args)
.derive_default(true) .derive_default(true)
.derive_debug(true) .derive_debug(true)
.parse_callbacks(Box::new(Wee8Renamer {})) .parse_callbacks(Box::new(Wee8Renamer {}))

View File

@@ -1,4 +1,4 @@
//! Data types, functions and traits for the `sys` runtime. //! Data types, functions and traits for the `js` backend.
pub(crate) mod entities; pub(crate) mod entities;
pub(crate) mod error; pub(crate) mod error;

View File

@@ -1,4 +1,4 @@
//! Data types, functions and traits for the `sys` runtime. //! Data types, functions and traits for the `jsc` backend.
pub(crate) mod entities; pub(crate) mod entities;
pub(crate) mod error; pub(crate) mod error;

View File

@@ -59,3 +59,93 @@ pub enum BackendKind {
/// The `jsc` runtime. /// The `jsc` runtime.
Jsc, Jsc,
} }
impl Default for BackendKind {
fn default() -> Self {
#[cfg(feature = "sys-default")]
{
#[cfg(feature = "cranelift")]
{
return Self::Cranelift;
}
#[cfg(feature = "singlepass")]
{
return Self::Singlepass;
}
#[cfg(feature = "llvm")]
{
return Self::LLVM;
}
return Self::Headless;
}
#[cfg(feature = "wamr-default")]
{
return Self::Wamr;
}
#[cfg(feature = "wasmi-default")]
{
return Self::Wasmi;
}
#[cfg(feature = "v8-default")]
{
return Self::V8;
}
#[cfg(feature = "js-default")]
{
return Self::Js;
}
#[cfg(feature = "jsc-default")]
{
return Self::Jsc;
}
#[cfg(feature = "sys")]
{
#[cfg(feature = "cranelift")]
{
return Self::Cranelift;
}
#[cfg(feature = "singlepass")]
{
return Self::Singlepass;
}
#[cfg(feature = "llvm")]
{
return Self::LLVM;
}
return Self::Headless;
}
#[cfg(feature = "wamr")]
{
return Self::Wamr;
}
#[cfg(feature = "wasmi")]
{
return Self::Wasmi;
}
#[cfg(feature = "v8")]
{
return Self::V8;
}
#[cfg(feature = "js")]
{
return Self::Js;
}
#[cfg(feature = "jsc")]
{
return Self::Jsc;
}
panic!("No runtime enabled!")
}
}

View File

@@ -28,7 +28,7 @@ pub fn get_default_compiler_config() -> Option<Box<dyn wasmer_compiler::Compiler
} }
/// Returns the default engine for the Sys engine /// Returns the default engine for the Sys engine
pub(crate) fn default_engine() -> Engine { pub fn default_engine() -> Engine {
#[allow(unreachable_code, unused_mut)] #[allow(unreachable_code, unused_mut)]
fn get_engine() -> Engine { fn get_engine() -> Engine {
cfg_if::cfg_if! { cfg_if::cfg_if! {

View File

@@ -33,12 +33,28 @@ impl Memory {
let mut store_mut = store.as_store_mut(); let mut store_mut = store.as_store_mut();
let v8_store = store_mut.inner.store.as_v8(); let v8_store = store_mut.inner.store.as_v8();
let max_requested = ty.maximum.unwrap_or(Pages::max_value());
let min = ty.minimum.0;
let max = max_requested.0;
if max < min {
return Err(MemoryError::InvalidMemory {
reason: format!("the maximum ({max} pages) is less than the minimum ({min} pages)",),
});
}
let max_allowed = Pages::max_value();
if max_requested > max_allowed {
return Err(MemoryError::MaximumMemoryTooLarge {
max_requested,
max_allowed,
});
}
let limits = Box::into_raw(Box::new(wasm_limits_t { let limits = Box::into_raw(Box::new(wasm_limits_t {
min: ty.minimum.0, min,
max: match ty.maximum { max,
Some(v) => v.0,
None => wasm_limits_max_default,
},
shared: ty.shared, shared: ty.shared,
})); }));

View File

@@ -222,7 +222,7 @@ impl Module {
let off = usize::from_ne_bytes(off.try_into().unwrap()); let off = usize::from_ne_bytes(off.try_into().unwrap());
let name_bytes = &binary[8..(8 + off)]; let name_bytes = &binary[8..(8 + off)];
let name = String::from_utf8_lossy(name_bytes).to_string(); let name = String::from_utf8_lossy(name_bytes).to_string();
let mod_bytes = &binary[off..]; let mod_bytes = &binary[(8 + off)..];
let module = ModuleHandle::deserialize(engine, mod_bytes)?; let module = ModuleHandle::deserialize(engine, mod_bytes)?;
Ok(Self { Ok(Self {
@@ -275,7 +275,12 @@ impl Module {
wasm_module_imports(module as *const _, &mut imports as *mut _); wasm_module_imports(module as *const _, &mut imports as *mut _);
let imports = std::slice::from_raw_parts(imports.data, imports.size).to_vec(); let imports =
if imports.data.is_null() || !imports.data.is_aligned() || imports.size == 0 {
vec![]
} else {
std::slice::from_raw_parts(imports.data, imports.size).to_vec()
};
let mut wasmer_imports = vec![]; let mut wasmer_imports = vec![];
for i in imports.into_iter() { for i in imports.into_iter() {
@@ -287,9 +292,17 @@ impl Module {
let name = std::slice::from_raw_parts((*name).data as *const u8, (*name).size); let name = std::slice::from_raw_parts((*name).data as *const u8, (*name).size);
let name_str = String::from_utf8_lossy(name).to_string(); let name_str = String::from_utf8_lossy(name).to_string();
let module = wasm_importtype_module(i as *const _); let module = wasm_importtype_module(i as *const _);
let module = let module_str = if module.is_null()
std::slice::from_raw_parts((*module).data as *const u8, (*module).size); || (*module).data.is_null()
let module_str = String::from_utf8_lossy(module).to_string(); || !(*module).data.is_aligned()
|| (*module).size == 0
{
String::new()
} else {
let str =
std::slice::from_raw_parts((*module).data as *const u8, (*module).size);
String::from_utf8_lossy(str).to_string()
};
let ty = IntoWasmerExternType::into_wextt(wasm_importtype_type(i as *const _)); let ty = IntoWasmerExternType::into_wextt(wasm_importtype_type(i as *const _));
if ty.is_err() { if ty.is_err() {

View File

@@ -1,4 +1,4 @@
//! Data types, functions and traits for the `sys` runtime. //! Data types, functions and traits for the `v8` backend.
pub(crate) mod bindings; pub(crate) mod bindings;
pub(crate) mod entities; pub(crate) mod entities;

View File

@@ -1,6 +1,7 @@
//! Data types, functions and traits for `wamr`'s `Instance` implementation. //! Data types, functions and traits for `wamr`'s `Instance` implementation.
use std::sync::Arc; use std::sync::Arc;
use crate::entities::external::VMExternToExtern;
use crate::{ use crate::{
backend::wamr::bindings::*, vm::VMExtern, wamr::error::Trap, AsStoreMut, AsStoreRef, Exports, backend::wamr::bindings::*, vm::VMExtern, wamr::error::Trap, AsStoreMut, AsStoreRef, Exports,
Extern, Imports, InstantiationError, Module, Extern, Imports, InstantiationError, Module,
@@ -39,17 +40,7 @@ impl InstanceHandle {
std::mem::forget(externs); std::mem::forget(externs);
let stack_size = 2 * 1024 * 1024; wasm_instance_new(store, module, &mut imports, &mut trap)
let heap_size = 2 * 1024 * 1024;
wasm_instance_new_with_args(
store,
module,
&mut imports,
&mut trap,
stack_size,
heap_size,
)
}; };
if instance.is_null() { if instance.is_null() {
@@ -61,29 +52,66 @@ impl InstanceHandle {
} }
fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports { fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports {
let mut exports = unsafe { let mut c_api_externs = unsafe {
let mut vec = Default::default(); let mut vec = Default::default();
wasm_instance_exports(self.0, &mut vec); wasm_instance_exports(self.0, &mut vec);
vec vec
}; };
let wasm_exports: &[*mut wasm_extern_t] = let c_api_externs: Vec<*mut wasm_extern_t> = if c_api_externs.data.is_null()
unsafe { std::slice::from_raw_parts(exports.data, exports.size) }; || !c_api_externs.data.is_aligned()
|| c_api_externs.size == 0
{
vec![]
} else {
unsafe { std::slice::from_raw_parts(c_api_externs.data, c_api_externs.size) }.to_vec()
};
let c_api_externs = c_api_externs.to_vec();
let mut exports = unsafe {
let mut vec = Default::default();
wasm_module_exports(module.as_wamr().handle.inner, &mut vec);
vec
};
let exports_ty = module.exports().collect::<Vec<_>>(); let c_api_exports: Vec<*mut wasm_exporttype_t> =
let exports = exports_ty if exports.data.is_null() || !exports.data.is_aligned() || exports.size == 0 {
.iter() vec![]
.zip(wasm_exports.into_iter()) } else {
.map(|(export_type, wasm_export)| { unsafe { std::slice::from_raw_parts(exports.data, exports.size) }.to_vec()
let name = export_type.name(); };
let mut store = store.as_store_mut();
let extern_type = export_type.ty();
// Annotation is here to prevent spurious IDE warnings.
let extern_ = Extern::from_vm_extern(&mut store, VMExtern::Wamr(*wasm_export)); // We need to use the order of the exports from the polyfill info to get the right
(name.to_string(), extern_) // one, i.e. the from the declaration.
let module_exports = module.exports().collect::<Vec<_>>();
let c_api_exports: Exports = c_api_exports
.into_iter()
.zip(c_api_externs.into_iter())
.map(|(export, ext)| unsafe {
let name = wasm_exporttype_name(export);
let name = std::slice::from_raw_parts((*name).data as *const u8, (*name).size);
let mut name = name.to_vec();
// Remove the '\0' at the end of the NULL-terminated string.
name.pop();
let name = String::from_utf8(name.to_vec()).unwrap_or_default();
let ext = ext.to_extern(&mut store);
(name, ext)
}) })
.collect::<Exports>(); .collect();
let mut exports = Exports::new();
for e in module_exports {
let ext: Extern = c_api_exports
.get::<Extern>(e.name())
.expect(&format!(
"c_api_exports: {c_api_exports:?} (name: {})",
e.name()
))
.clone();
exports.insert(e.name().to_string(), ext);
}
exports exports
} }
} }

View File

@@ -9,14 +9,7 @@ use wasmer_types::{MemoryType, Pages, WASM_PAGE_SIZE};
use crate::{ use crate::{
shared::SharedMemory, shared::SharedMemory,
vm::{VMExtern, VMExternMemory}, vm::{VMExtern, VMExternMemory},
wamr::{ wamr::{bindings::*, vm::VMMemory},
bindings::{
wasm_limits_max_default, wasm_limits_t, wasm_memory_as_extern, wasm_memory_copy,
wasm_memory_new, wasm_memory_type, wasm_memorytype_limits, wasm_memorytype_new,
wasm_memorytype_t,
},
vm::VMMemory,
},
AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError,
}; };
@@ -34,14 +27,28 @@ unsafe impl Sync for Memory {}
impl Memory { impl Memory {
pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> { pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
let limits = Box::into_raw(Box::new(wasm_limits_t { let max_requested = ty.maximum.unwrap_or(Pages::max_value());
min: ty.minimum.0,
max: match ty.maximum {
Some(v) => v.0,
None => wasm_limits_max_default,
},
}));
let min = ty.minimum.0;
let max = max_requested.0;
if max < min {
return Err(MemoryError::InvalidMemory {
reason: format!("the maximum ({max} pages) is less than the minimum ({min} pages)",),
});
}
let max_allowed = Pages::max_value();
if max_requested > max_allowed {
return Err(MemoryError::MaximumMemoryTooLarge {
max_requested,
max_allowed,
});
}
let limits = Box::into_raw(Box::new(wasm_limits_t { min, max }));
eprintln!("limits: {limits:?}");
let memorytype = unsafe { wasm_memorytype_new(limits) }; let memorytype = unsafe { wasm_memorytype_new(limits) };
let mut store = store.as_store_mut(); let mut store = store.as_store_mut();

View File

@@ -1,12 +1,7 @@
//! Data types, functions and traits for `wamr`'s `Module` implementation. //! Data types, functions and traits for `wamr`'s `Module` implementation.
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use crate::{ use crate::{backend::wamr::bindings::*, AsEngineRef, BackendModule, IntoBytes};
backend::wamr::bindings::{
wasm_byte_vec_t, wasm_module_delete, wasm_module_new, wasm_module_t,
},
AsEngineRef, BackendModule, IntoBytes,
};
use bytes::Bytes; use bytes::Bytes;
use wasmer_types::{ use wasmer_types::{
@@ -97,8 +92,25 @@ impl Module {
} }
pub fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> { pub fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> {
let engine = engine.as_engine_ref(); let engine = engine.as_engine_ref().engine().clone();
unimplemented!(); let store = super::store::Store::new(engine);
let bytes = wasm_byte_vec_t {
size: binary.len(),
data: binary.as_ptr() as _,
num_elems: binary.len(),
size_of_elem: 1,
lock: std::ptr::null_mut(),
};
let store = store.inner;
unsafe {
if !wasm_module_validate(store, &bytes as *const _) {
return Err(CompileError::Validate(String::from(
"WAMR could not validate the given module",
)));
}
}
Ok(())
} }
pub fn name(&self) -> Option<&str> { pub fn name(&self) -> Option<&str> {

View File

@@ -1,4 +1,4 @@
//! Data types, functions and traits for `wamr`. //! Data types, functions and traits for the `wamr` backend.
pub(crate) mod bindings; pub(crate) mod bindings;
pub(crate) mod entities; pub(crate) mod entities;

View File

@@ -2,8 +2,9 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
backend::wasmi::bindings::*, vm::VMExtern, wasmi::error::Trap, AsStoreMut, AsStoreRef, Exports, backend::wasmi::bindings::*, entities::external::VMExternToExtern, vm::VMExtern,
Extern, Imports, InstantiationError, Module, wasmi::error::Trap, AsStoreMut, AsStoreRef, Exports, Extern, Imports, InstantiationError,
Module,
}; };
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
@@ -51,29 +52,48 @@ impl InstanceHandle {
} }
fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports { fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports {
let mut exports = unsafe { let mut c_api_externs = unsafe {
let mut vec = Default::default(); let mut vec = Default::default();
wasm_instance_exports(self.0, &mut vec); wasm_instance_exports(self.0, &mut vec);
vec vec
}; };
let wasm_exports: &[*mut wasm_extern_t] = let c_api_externs: &[*mut wasm_extern_t] =
unsafe { std::slice::from_raw_parts(c_api_externs.data, c_api_externs.size) };
let c_api_externs = c_api_externs.to_vec();
let mut exports = unsafe {
let mut vec = Default::default();
wasm_module_exports(module.as_wasmi().handle.inner, &mut vec);
vec
};
let c_api_exports: &[*mut wasm_exporttype_t] =
unsafe { std::slice::from_raw_parts(exports.data, exports.size) }; unsafe { std::slice::from_raw_parts(exports.data, exports.size) };
let c_api_exports = c_api_exports.to_vec();
let exports_ty = module.exports().collect::<Vec<_>>(); // We need to use the order of the exports from the polyfill info to get the right
let exports = exports_ty // one, i.e. the from the declaration.
.iter() let module_exports = module.exports().collect::<Vec<_>>();
.zip(wasm_exports.into_iter())
.map(|(export_type, wasm_export)| {
let name = export_type.name();
let mut store = store.as_store_mut();
let extern_type = export_type.ty();
// Annotation is here to prevent spurious IDE warnings.
let extern_ = Extern::from_vm_extern(&mut store, VMExtern::Wasmi(*wasm_export)); let c_api_exports: Exports = c_api_exports
(name.to_string(), extern_) .into_iter()
.zip(c_api_externs.into_iter())
.map(|(export, ext)| unsafe {
let name = wasm_exporttype_name(export);
let name = std::slice::from_raw_parts((*name).data as *const u8, (*name).size);
let name = String::from_utf8(name.to_vec()).unwrap_or_default();
let ext = ext.to_extern(&mut store);
(name, ext)
}) })
.collect::<Exports>(); .collect();
let mut exports = Exports::new();
for e in module_exports {
let ext: Extern = c_api_exports.get::<Extern>(e.name()).unwrap().clone();
exports.insert(e.name().to_string(), ext);
}
exports exports
} }
} }

View File

@@ -27,13 +27,26 @@ unsafe impl Sync for Memory {}
impl Memory { impl Memory {
pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> { pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
let limits = Box::into_raw(Box::new(wasm_limits_t { let max_requested = ty.maximum.unwrap_or(Pages::max_value());
min: ty.minimum.0,
max: match ty.maximum { let min = ty.minimum.0;
Some(v) => v.0, let max = max_requested.0;
None => wasm_limits_max_default,
}, if max < min {
})); return Err(MemoryError::InvalidMemory {
reason: format!("the maximum ({max} pages) is less than the minimum ({min} pages)",),
});
}
let max_allowed = Pages::max_value();
if max_requested > max_allowed {
return Err(MemoryError::MaximumMemoryTooLarge {
max_requested,
max_allowed,
});
}
let limits = Box::into_raw(Box::new(wasm_limits_t { min, max }));
let memorytype = unsafe { wasm_memorytype_new(limits) }; let memorytype = unsafe { wasm_memorytype_new(limits) };

View File

@@ -1,4 +1,4 @@
//! Data types, functions and traits for `wasmi`. //! Data types, functions and traits for the `wasmi` backend.
pub(crate) mod bindings; pub(crate) mod bindings;
pub(crate) mod entities; pub(crate) mod entities;

View File

@@ -66,43 +66,76 @@ wasmer-inline-c = "0.1.1"
inline-c = "0.1.7" inline-c = "0.1.7"
[features] [features]
default = ["wat", "cranelift", "compiler", "wasi", "middlewares"] default = ["wat", "sys-default", "cranelift", "compiler", "wasi", "middlewares"]
sys = []
jsc = ["wasmer-api/jsc", "wasmer-api/std"]
wat = ["wasmer-api/wat"] wat = ["wasmer-api/wat"]
wasi = ["wasmer-wasix"] wasi = ["wasmer-wasix"]
middlewares = ["compiler", "wasmer-middlewares"] middlewares = ["compiler", "wasmer-middlewares"]
# Enable the `sys` backend.
sys = []
# Enable the `singlepass` compiler.
singlepass = [
"dep:wasmer-compiler-singlepass",
"wasmer-api/singlepass",
"compiler",
]
# Enable the `cranelift` compiler.
cranelift = [
"dep:wasmer-compiler-cranelift",
"wasmer-api/cranelift",
"compiler",
]
# Enable the `llvm` compiler.
llvm = ["dep:wasmer-compiler-llvm", "wasmer-api/llvm", "compiler"]
# Enable the use of compiler. Implies enabling the `sys` feature.
compiler = [ compiler = [
"sys",
"wasmer-compiler", "wasmer-compiler",
"wasmer-api/compiler", "wasmer-api/compiler",
"wasmer-compiler/translator", "wasmer-compiler/translator",
"wasmer-compiler/compiler", "wasmer-compiler/compiler",
] ]
# Enable the use of the headless compiler. Implies enabling the `sys` feature.
compiler-headless = [ compiler-headless = [
"sys",
"wasmer-artifact-load", "wasmer-artifact-load",
"static-artifact-load", "static-artifact-load",
"wasmer-api/compiler", "wasmer-api/compiler",
"wasmer-compiler/translator", "wasmer-compiler/translator",
"wasmer-compiler/compiler", "wasmer-compiler/compiler",
] ]
singlepass = ["wasmer-compiler-singlepass", "compiler"]
cranelift = ["wasmer-compiler-cranelift", "compiler"]
llvm = ["wasmer-compiler-llvm", "compiler"]
############ # Enable the `jsc` backend.
# WARNING! # jsc = ["wasmer-api/jsc", "wasmer-api/std"]
############
# These features are here but, for now (wasmer 6.0.0-alpha1) they do nothing.
# In the next alpha release they will be wired up to use the matching backend.
# These features are being added now to make CI easier, since we will
# nonetheless have to add them later.
v8 = [] # Enable the `v8` backend.
wasmi = [] v8 = ["wasmer-api/v8"]
wamr = []
############ # Enable the `wasmi` backend.
############ wasmi = ["wasmer-api/wasmi"]
# Enable the `wamr` backend.
wamr = ["wasmer-api/wamr"]
# Enable the `sys` backend and use it as default. Notice that this does not
# enable a default compiler, and users should therefore add one (or more) of
# the `singlepass`, `cranelift` and `llvm` features.
sys-default = ["sys", "wasmer-api/sys-default"]
# Enable the `jsc` backend and use it as default.
jsc-default = ["jsc", "wasmer-api/jsc-default"]
# Enable the `v8` backend and use it as default.
v8-default = ["v8", "wasmer-api/v8-default"]
# Enable the `wamr` backend and use it as default.
wamr-default = ["wamr", "wasmer-api/wamr-default"]
# Enable the `wasmi` backend and use it as default.
wasmi-default = ["wasmi", "wasmer-api/wasmi-default"]
wasmer-artifact-load = ["wasmer-compiler/wasmer-artifact-load"] wasmer-artifact-load = ["wasmer-compiler/wasmer-artifact-load"]
wasmer-artifact-create = ["wasmer-compiler/wasmer-artifact-create"] wasmer-artifact-create = ["wasmer-compiler/wasmer-artifact-create"]

View File

@@ -25,7 +25,10 @@
)] )]
// Because this crate exposes a lot of C APIs which are unsafe by definition, // Because this crate exposes a lot of C APIs which are unsafe by definition,
// we allow unsafe without explicit safety documentation for each of them. // we allow unsafe without explicit safety documentation for each of them.
//
// For the same reason, we also turn off the warning for camel_case types.
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
#![allow(non_camel_case_types)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
pub mod error; pub mod error;

View File

@@ -1,493 +0,0 @@
pub use super::unstable::engine::wasm_config_set_features;
use super::unstable::features::wasmer_features_t;
use crate::error::update_last_error;
use cfg_if::cfg_if;
#[cfg(feature = "compiler")]
pub use super::unstable::engine::{wasm_config_set_target, wasmer_is_compiler_available};
#[cfg(any(feature = "compiler", feature = "compiler-headless"))]
use super::unstable::target_lexicon::wasmer_target_t;
#[cfg(feature = "middlewares")]
pub use super::unstable::middlewares::wasm_config_push_middleware;
#[cfg(feature = "middlewares")]
use super::unstable::middlewares::wasmer_middleware_t;
#[cfg(any(feature = "compiler", feature = "compiler-headless"))]
use wasmer_compiler::{Engine, EngineBuilder};
#[cfg(not(any(feature = "compiler", feature = "compiler-headless")))]
use wasmer_api::Engine;
/// Kind of compilers that can be used by the engines.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
#[cfg(feature = "compiler")]
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum wasmer_compiler_t {
/// Variant to represent the Cranelift compiler. See the
/// [`wasmer_compiler_cranelift`] Rust crate.
CRANELIFT = 0,
/// Variant to represent the LLVM compiler. See the
/// [`wasmer_compiler_llvm`] Rust crate.
LLVM = 1,
/// Variant to represent the Singlepass compiler. See the
/// [`wasmer_compiler_singlepass`] Rust crate.
SINGLEPASS = 2,
}
#[cfg(feature = "compiler")]
impl Default for wasmer_compiler_t {
fn default() -> Self {
cfg_if! {
if #[cfg(feature = "cranelift")] {
Self::CRANELIFT
} else if #[cfg(feature = "llvm")] {
Self::LLVM
} else if #[cfg(feature = "singlepass")] {
Self::SINGLEPASS
} else {
compile_error!("Please enable one of the compiler backends")
}
}
}
}
/// Kind of engines that can be used by the store.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
#[derive(Debug, Copy, Clone)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum wasmer_engine_t {
/// Variant to represent the Universal engine. See the
/// [`wasmer_engine_universal`] Rust crate.
UNIVERSAL = 0,
}
impl Default for wasmer_engine_t {
fn default() -> Self {
Self::UNIVERSAL
}
}
/// A configuration holds the compiler and the engine used by the store.
///
/// cbindgen:ignore
#[derive(Debug, Default)]
#[repr(C)]
pub struct wasm_config_t {
engine: wasmer_engine_t,
#[cfg(feature = "compiler")]
compiler: wasmer_compiler_t,
#[cfg(feature = "middlewares")]
pub(super) middlewares: Vec<wasmer_middleware_t>,
pub(super) nan_canonicalization: bool,
pub(super) features: Option<Box<wasmer_features_t>>,
#[cfg(any(feature = "compiler", feature = "compiler-headless"))]
pub(super) target: Option<Box<wasmer_target_t>>,
}
/// Create a new default Wasmer configuration.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_config_new() -> Box<wasm_config_t> {
Box::<wasm_config_t>::default()
}
/// Delete a Wasmer config object.
///
/// This function does not need to be called if `wasm_engine_new_with_config` or
/// another function that takes ownership of the `wasm_config_t` is called.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Delete the configuration
/// wasm_config_delete(config);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_config_delete(_config: Option<Box<wasm_config_t>>) {}
/// Updates the configuration to specify a particular compiler to use.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Use the Cranelift compiler, if available.
/// if (wasmer_is_compiler_available(CRANELIFT)) {
/// wasm_config_set_compiler(config, CRANELIFT);
/// }
/// // Or maybe LLVM?
/// else if (wasmer_is_compiler_available(LLVM)) {
/// wasm_config_set_compiler(config, LLVM);
/// }
/// // Or maybe Singlepass?
/// else if (wasmer_is_compiler_available(SINGLEPASS)) {
/// wasm_config_set_compiler(config, SINGLEPASS);
/// }
/// // OK, let's run with no particular compiler.
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[cfg(feature = "compiler")]
#[no_mangle]
pub extern "C" fn wasm_config_set_compiler(
config: &mut wasm_config_t,
compiler: wasmer_compiler_t,
) {
config.compiler = compiler;
}
/// Updates the configuration to specify a particular engine to use.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[no_mangle]
pub extern "C" fn wasm_config_set_engine(config: &mut wasm_config_t, engine: wasmer_engine_t) {
config.engine = engine;
}
/// An engine is used by the store to drive the compilation and the
/// execution of a WebAssembly module.
///
/// cbindgen:ignore
#[repr(C)]
pub struct wasm_engine_t {
pub(crate) inner: Engine,
}
#[cfg(feature = "compiler")]
use wasmer_api::sys::CompilerConfig;
#[cfg(feature = "compiler")]
fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
cfg_if! {
if #[cfg(feature = "cranelift")] {
Box::<wasmer_compiler_cranelift::Cranelift>::default()
} else if #[cfg(feature = "llvm")] {
Box::<wasmer_compiler_llvm::LLVM>::default()
} else if #[cfg(feature = "singlepass")] {
Box::<wasmer_compiler_singlepass::Singlepass>::default()
} else {
compile_error!("Please enable one of the compiler backends")
}
}
}
cfg_if! {
if #[cfg(feature = "compiler")] {
/// Creates a new Universal engine with the default compiler.
///
/// # Example
///
/// See [`wasm_engine_delete`].
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
let engine: Engine = EngineBuilder::new(compiler_config).engine();
Box::new(wasm_engine_t { inner: engine })
}
} else if #[cfg(feature = "compiler-headless")] {
/// Creates a new headless Universal engine.
///
/// # Example
///
/// See [`wasm_engine_delete`].
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let engine: Engine = EngineBuilder::headless().engine();
Box::new(wasm_engine_t { inner: engine })
}
} else if #[cfg(feature = "jsc")] {
/// Creates the JavascriptCore Engine.
///
/// # Example
///
/// See [`wasm_engine_delete`].
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
let engine: Engine = Engine::default();
Box::new(wasm_engine_t { inner: engine })
}
} else {
/// Creates a new unknown engine, i.e. it will panic with an error message.
///
/// # Example
///
/// See [`wasm_engine_delete`].
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
unimplemented!("No engine attached; You might want to recompile `wasmer_c_api` with for example `--feature compiler`");
}
}
}
/// Deletes an engine.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create a default engine.
/// wasm_engine_t* engine = wasm_engine_new();
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
///
/// cbindgen:ignore
#[no_mangle]
pub unsafe extern "C" fn wasm_engine_delete(_engine: Option<Box<wasm_engine_t>>) {}
/// Creates an engine with a particular configuration.
///
/// # Example
///
/// See [`wasm_config_new`].
///
/// cbindgen:ignore
#[no_mangle]
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(msg: &str) -> Option<Box<wasm_engine_t>> {
update_last_error(msg);
None
}
#[allow(unused)]
let config = config?;
//#[cfg(not(any(feature = "compiler", feature = "compiler-headless")))]
//return return_with_error("Wasmer has not been compiled with the `compiler` feature.");
cfg_if! {
if #[cfg(feature = "compiler")] {
#[allow(unused_mut)]
let mut compiler_config: Box<dyn CompilerConfig> = match config.compiler {
wasmer_compiler_t::CRANELIFT => {
cfg_if! {
if #[cfg(feature = "cranelift")] {
Box::<wasmer_compiler_cranelift::Cranelift>::default()
} else {
return return_with_error("Wasmer has not been compiled with the `cranelift` feature.");
}
}
},
wasmer_compiler_t::LLVM => {
cfg_if! {
if #[cfg(feature = "llvm")] {
Box::<wasmer_compiler_llvm::LLVM>::default()
} else {
return return_with_error("Wasmer has not been compiled with the `llvm` feature.");
}
}
},
wasmer_compiler_t::SINGLEPASS => {
cfg_if! {
if #[cfg(feature = "singlepass")] {
Box::<wasmer_compiler_singlepass::Singlepass>::default()
} else {
return return_with_error("Wasmer has not been compiled with the `singlepass` feature.");
}
}
},
};
#[cfg(feature = "middlewares")]
for middleware in config.middlewares {
compiler_config.push_middleware(middleware.inner);
}
if config.nan_canonicalization {
compiler_config.canonicalize_nans(true);
}
let inner: Engine =
{
let mut builder = EngineBuilder::new(compiler_config);
if let Some(target) = config.target {
builder = builder.set_target(Some(target.inner));
}
if let Some(features) = config.features {
builder = builder.set_features(Some(features.inner));
}
builder.engine()
};
Some(Box::new(wasm_engine_t { inner }))
} else {
#[cfg(feature = "compiler-headless")]
let inner: Engine =
{
let mut builder = EngineBuilder::headless();
if let Some(target) = config.target {
builder = builder.set_target(Some(target.inner));
}
if let Some(features) = config.features {
builder = builder.set_features(Some(features.inner));
}
builder.engine()
};
#[cfg(not(any(feature = "compiler-headless", feature="compiler")))]
let inner: Engine = Engine::default();
Some(Box::new(wasm_engine_t { inner }))
}
}
}
#[cfg(test)]
mod tests {
#[cfg(not(target_os = "windows"))]
use inline_c::assert_c;
#[cfg(target_os = "windows")]
use wasmer_inline_c::assert_c;
#[cfg_attr(coverage, ignore)]
#[test]
fn test_engine_new() {
(assert_c! {
#include "tests/wasmer.h"
int main() {
wasm_engine_t* engine = wasm_engine_new();
assert(engine);
wasm_engine_delete(engine);
return 0;
}
})
.success();
}
}

View File

@@ -0,0 +1,38 @@
use crate::{
error::update_last_error,
wasm_c_api::engine::{wasm_config_t, wasm_engine_t, wasmer_backend_t},
};
use super::wasmer_backend_config_kind_t;
/// Configuration specific for the `jsc` engine.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
///
/// cbindgen:ignore
#[repr(C)]
#[derive(Debug, Default)]
pub(crate) struct wasmer_jsc_engine_config_t;
/// Create a new [`wasm_engine_t`] backed by a `jsc` engine.
pub(crate) fn wasm_jsc_engine_new_with_config(config: wasm_config_t) -> Option<Box<wasm_engine_t>> {
if !matches!(config.backend, wasmer_backend_t::JSC) || !config.backend_config.inner.is_jsc() {
update_last_error("Cannot create a new `jsc` engine with a non-jsc-specific config!");
return None;
}
Some(Box::new(wasm_engine_t {
inner: wasmer_api::jsc::Engine::default().into(),
}))
}
impl wasmer_backend_config_kind_t {
/// Returns `true` if the wasmer_engine_config_t is [`Jsc`].
///
/// [`Jsc`]: wasmer_engine_config_t::Jsc
#[must_use]
pub(super) fn is_jsc(&self) -> bool {
matches!(self, Self::Jsc(..))
}
}

View File

@@ -0,0 +1,145 @@
#[cfg(feature = "sys")]
pub(crate) mod sys;
#[cfg(feature = "sys")]
pub use sys::*;
use crate::wasm_c_api::unstable::target_lexicon::wasmer_target_t;
use super::{wasm_config_t, wasmer_backend_t};
#[cfg(feature = "jsc")]
pub(crate) mod jsc;
#[cfg(feature = "v8")]
pub(crate) mod v8;
#[cfg(feature = "wasmi")]
pub(crate) mod wasmi;
#[cfg(feature = "wamr")]
pub(crate) mod wamr;
#[repr(C)]
#[derive(Debug)]
pub(crate) enum wasmer_backend_config_kind_t {
#[cfg(feature = "sys")]
Sys(sys::wasmer_sys_engine_config_t),
#[cfg(feature = "jsc")]
Jsc(jsc::wasmer_jsc_engine_config_t),
#[cfg(feature = "v8")]
V8(v8::wasmer_v8_engine_config_t),
#[cfg(feature = "wasmi")]
Wasmi(wasmi::wasmer_wasmi_engine_config_t),
#[cfg(feature = "wamr")]
Wamr(wamr::wasmer_wamr_engine_config_t),
}
impl Default for wasmer_backend_config_kind_t {
fn default() -> Self {
match wasmer_backend_t::default() {
#[cfg(feature = "llvm")]
super::wasmer_backend_t::LLVM => Self::Sys(sys::wasmer_sys_engine_config_t::default()),
#[cfg(feature = "cranelift")]
super::wasmer_backend_t::CRANELIFT => {
Self::Sys(sys::wasmer_sys_engine_config_t::default())
}
#[cfg(feature = "singlepass")]
super::wasmer_backend_t::SINGLEPASS => {
Self::Sys(sys::wasmer_sys_engine_config_t::default())
}
#[cfg(feature = "sys")]
super::wasmer_backend_t::HEADLESS => {
Self::Sys(sys::wasmer_sys_engine_config_t::default())
}
#[cfg(feature = "v8")]
super::wasmer_backend_t::V8 => Self::V8(v8::wasmer_v8_engine_config_t::default()),
#[cfg(feature = "wasmi")]
super::wasmer_backend_t::WASMI => {
Self::Wasmi(wasmi::wasmer_wasmi_engine_config_t::default())
}
#[cfg(feature = "wamr")]
super::wasmer_backend_t::WAMR => {
Self::Wamr(wamr::wasmer_wamr_engine_config_t::default())
}
#[cfg(feature = "jsc")]
super::wasmer_backend_t::JSC => Self::Jsc(jsc::wasmer_jsc_engine_config_t::default()),
_ => unreachable!(),
}
}
}
#[repr(C)]
#[derive(Debug, Default)]
pub(crate) struct wasmer_backend_config_t {
pub inner: wasmer_backend_config_kind_t,
pub target: Option<Box<wasmer_target_t>>,
#[cfg(feature = "middlewares")]
pub middlewares: Vec<wasmer_middleware_t>,
}
/// Unstable non-standard Wasmer-specific API to update the
/// configuration to specify a particular target for the engine.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Set the target.
/// {
/// wasmer_triple_t* triple = wasmer_triple_new_from_host();
/// wasmer_cpu_features_t* cpu_features = wasmer_cpu_features_new();
/// wasmer_target_t* target = wasmer_target_new(triple, cpu_features);
///
/// wasm_config_sys_set_target(config, target);
/// }
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[no_mangle]
pub extern "C" fn wasm_config_set_target(config: &mut wasm_config_t, target: Box<wasmer_target_t>) {
config.backend_config.target = Some(target);
}
/// Updates the configuration to add a module middleware.
///
/// This function takes ownership of `middleware`.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// See the documentation of the [`metering`] module.
#[no_mangle]
#[cfg(feature = "middlewares")]
pub extern "C" fn wasm_config_push_middleware(
config: &mut wasm_config_t,
middleware: Box<wasmer_middleware_t>,
) {
config.backend_config.middlewares.push(*middleware)
}

View File

@@ -0,0 +1,205 @@
// Necessary when a single backend is enabled.
#![allow(irrefutable_let_patterns)]
use crate::{
error::update_last_error,
wasm_c_api::engine::{
wasm_config_t, wasm_engine_t, wasmer_backend_config_kind_t, wasmer_backend_t,
},
};
#[cfg(feature = "middlewares")]
pub use crate::wasm_c_api::unstable::middlewares::wasmer_middleware_t;
use cfg_if::cfg_if;
use wasmer_api::Engine;
use wasmer_compiler::EngineBuilder;
#[cfg(feature = "compiler")]
use wasmer_api::sys::CompilerConfig;
/// Configuration specific for `sys` (Cranelift, LLVM, Singlepass) engines.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for manipulating it.
///
/// cbindgen:ignore
#[repr(C)]
#[derive(Debug, Default)]
pub(crate) struct wasmer_sys_engine_config_t {
pub nan_canonicalization: bool,
}
/// Updates the configuration to enable NaN canonicalization.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Enable NaN canonicalization.
/// wasm_config_sys_canonicalize_nans(config, true);
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[no_mangle]
pub extern "C" fn wasm_config_sys_canonicalize_nans(config: &mut wasm_config_t, enable: bool) {
if let wasmer_backend_config_kind_t::Sys(ref mut c) = config.backend_config.inner {
c.nan_canonicalization = enable;
} else {
let sys_config = wasmer_sys_engine_config_t {
nan_canonicalization: enable,
};
config.backend_config.inner = wasmer_backend_config_kind_t::Sys(sys_config);
}
}
/// Create a new [`wasm_engine_t`] backed by a `sys` engine.
pub fn wasm_sys_engine_new_with_config(config: wasm_config_t) -> Option<Box<wasm_engine_t>> {
if !matches!(config.backend, wasmer_backend_t::LLVM)
&& !matches!(config.backend, wasmer_backend_t::SINGLEPASS)
&& !matches!(config.backend, wasmer_backend_t::CRANELIFT)
&& !matches!(config.backend, wasmer_backend_t::HEADLESS)
&& !config.backend_config.inner.is_sys()
{
update_last_error(format!(
"Cannot create a new `sys` engine with a non-sys-specific config! {config:?}"
));
return None;
}
let backend = config.backend;
#[allow(unused)]
let sys_config = match config.backend_config.inner.try_into_sys() {
Err(_) => {
update_last_error(format!(
"Could not create new `sys` engine with the selected {backend:?} backend."
));
return None;
}
Ok(s) => s,
};
cfg_if! {
if #[cfg(feature = "compiler")] {
#[allow(unused_mut)]
let mut compiler_config: Box<dyn CompilerConfig> = match &backend {
wasmer_backend_t::CRANELIFT => {
cfg_if! {
if #[cfg(feature = "cranelift")] {
Box::<wasmer_compiler_cranelift::Cranelift>::default()
} else {
update_last_error("Wasmer has not been compiled with the `cranelift` feature.");
return None;
}
}
},
wasmer_backend_t::LLVM => {
cfg_if! {
if #[cfg(feature = "llvm")] {
Box::<wasmer_compiler_llvm::LLVM>::default()
} else {
update_last_error("Wasmer has not been compiled with the `llvm` feature.");
return None;
}
}
},
wasmer_backend_t::SINGLEPASS => {
cfg_if! {
if #[cfg(feature = "singlepass")] {
Box::<wasmer_compiler_singlepass::Singlepass>::default()
} else {
update_last_error("Wasmer has not been compiled with the `singlepass` feature.");
return None;
}
}
},
_ => panic!("not a `sys` backend!")
};
#[cfg(feature = "middlewares")]
for middleware in config.backend_config.middlewares {
compiler_config.push_middleware(middleware.inner.clone());
}
if sys_config.nan_canonicalization {
compiler_config.canonicalize_nans(true);
}
let inner: Engine =
{
let mut builder = EngineBuilder::new(compiler_config);
if let Some(target) = config.backend_config.target {
builder = builder.set_target(Some(target.inner));
}
if let Some(features) = config.features {
builder = builder.set_features(Some(features.inner));
}
builder.engine().into()
};
Some(Box::new(wasm_engine_t { inner }))
} else if #[cfg(feature = "compiler-headless")] {
let inner: Engine =
{
let mut builder = EngineBuilder::headless();
if let Some(target) = config.backend_config.target {
builder = builder.set_target(Some(target.inner));
}
if let Some(features) = config.features {
builder = builder.set_features(Some(features.inner));
}
builder.engine().into()
};
Some(Box::new(wasm_engine_t { inner }))
} else {
update_last_error("No backend enabled for the `sys` engine: enable one of `compiler` or `compiler-headless`!");
return None;
}
}
}
impl wasmer_backend_config_kind_t {
/// Returns `true` if the wasmer_engine_config_t is [`Sys`].
///
/// [`Sys`]: wasmer_engine_config_t::Sys
#[must_use]
pub(super) fn is_sys(&self) -> bool {
matches!(self, Self::Sys(..))
}
pub(super) fn try_into_sys(self) -> Result<wasmer_sys_engine_config_t, Self> {
if let Self::Sys(v) = self {
Ok(v)
} else {
Err(self)
}
}
}

View File

@@ -0,0 +1,38 @@
use crate::{
error::update_last_error,
wasm_c_api::engine::{wasm_config_t, wasm_engine_t, wasmer_backend_t},
};
use super::wasmer_backend_config_kind_t;
/// Configuration specific for the `v8` engine.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
///
/// cbindgen:ignore
#[repr(C)]
#[derive(Debug, Default)]
pub(crate) struct wasmer_v8_engine_config_t;
/// Create a new [`wasm_engine_t`] backed by a `v8` engine.
pub(crate) fn wasm_v8_engine_new_with_config(config: wasm_config_t) -> Option<Box<wasm_engine_t>> {
if !matches!(config.backend, wasmer_backend_t::V8) || !config.backend_config.inner.is_v8() {
update_last_error("Cannot create a new `v8` engine with a non-v8-specific config!");
return None;
}
Some(Box::new(wasm_engine_t {
inner: wasmer_api::v8::V8::default().into(),
}))
}
impl wasmer_backend_config_kind_t {
/// Returns `true` if the wasmer_engine_config_t is [`V8`].
///
/// [`V8`]: wasmer_engine_config_t::V8
#[must_use]
pub(super) fn is_v8(&self) -> bool {
matches!(self, Self::V8(..))
}
}

View File

@@ -0,0 +1,40 @@
use crate::{
error::update_last_error,
wasm_c_api::engine::{wasm_config_t, wasm_engine_t, wasmer_backend_t},
};
use super::wasmer_backend_config_kind_t;
/// Configuration specific for the `wamr` engine.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
///
/// cbindgen:ignore
#[repr(C)]
#[derive(Debug, Default)]
pub(crate) struct wasmer_wamr_engine_config_t;
/// Create a new [`wasm_engine_t`] backed by a `wamr` engine.
pub(crate) fn wasm_wamr_engine_new_with_config(
config: wasm_config_t,
) -> Option<Box<wasm_engine_t>> {
if !matches!(config.backend, wasmer_backend_t::WAMR) || !config.backend_config.inner.is_wamr() {
update_last_error("Cannot create a new `wamr` engine with a non-wamr-specific config!");
return None;
}
Some(Box::new(wasm_engine_t {
inner: wasmer_api::wamr::Wamr::default().into(),
}))
}
impl wasmer_backend_config_kind_t {
/// Returns `true` if the wasmer_engine_config_t is [`WAMR`].
///
/// [`WAMR`]: wasmer_engine_config_t::WAMR
#[must_use]
pub(super) fn is_wamr(&self) -> bool {
matches!(self, Self::Wamr(..))
}
}

View File

@@ -0,0 +1,41 @@
use crate::{
error::update_last_error,
wasm_c_api::engine::{wasm_config_t, wasm_engine_t, wasmer_backend_t},
};
use super::wasmer_backend_config_kind_t;
/// Configuration specific for the `wasmi` engine.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
///
/// cbindgen:ignore
#[repr(C)]
#[derive(Debug, Default)]
pub(crate) struct wasmer_wasmi_engine_config_t;
/// Create a new [`wasm_engine_t`] backed by a `wasmi` engine.
pub(crate) fn wasm_wasmi_engine_new_with_config(
config: wasm_config_t,
) -> Option<Box<wasm_engine_t>> {
if !matches!(config.backend, wasmer_backend_t::WASMI) || !config.backend_config.inner.is_wasmi()
{
update_last_error("Cannot create a new `wasmi` engine with a non-wasmi-specific config!");
return None;
}
Some(Box::new(wasm_engine_t {
inner: wasmer_api::wasmi::Wasmi::default().into(),
}))
}
impl wasmer_backend_config_kind_t {
/// Returns `true` if the wasmer_engine_config_t is [`WASMI`].
///
/// [`WASMI`]: wasmer_engine_config_t::WASMI
#[must_use]
pub(super) fn is_wasmi(&self) -> bool {
matches!(self, Self::Wasmi(..))
}
}

View File

@@ -0,0 +1,306 @@
pub use super::unstable::engine::wasm_config_set_features;
use super::unstable::features::wasmer_features_t;
use wasmer_api::{BackendKind, Engine};
mod config;
#[allow(unused_imports)]
pub use config::*;
/// Kind of engines that can be used by the store.
///
/// This is a Wasmer-specific type with Wasmer-specific functions for
/// manipulating it.
#[derive(Debug, Copy, Clone)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum wasmer_backend_t {
/// The cranelift backend.
CRANELIFT = 0,
/// The LLVM backend.
LLVM,
/// The singlepass backend.
SINGLEPASS,
/// The headless backend.
HEADLESS,
/// The V8 backend.
V8,
/// The WASMI backend.
WASMI,
/// The WAMR backend.
WAMR,
/// The JSC backend.
JSC,
}
impl From<BackendKind> for wasmer_backend_t {
fn from(value: BackendKind) -> Self {
match value {
#[cfg(feature = "cranelift")]
BackendKind::Cranelift => Self::CRANELIFT,
#[cfg(feature = "llvm")]
BackendKind::LLVM => Self::LLVM,
#[cfg(feature = "singlepass")]
BackendKind::Singlepass => Self::SINGLEPASS,
#[cfg(feature = "sys")]
BackendKind::Headless => Self::HEADLESS,
#[cfg(feature = "wamr")]
BackendKind::Wamr => Self::WAMR,
#[cfg(feature = "wasmi")]
BackendKind::Wasmi => Self::WASMI,
#[cfg(feature = "v8")]
BackendKind::V8 => Self::V8,
#[cfg(feature = "jsc")]
BackendKind::Jsc => Self::JSC,
v => panic!("Unsupported backend kind {v:?}"),
}
}
}
impl Default for wasmer_backend_t {
fn default() -> Self {
// Let the `wasmer_api` crate decide which is the default engine, given the enabled
// features.
wasmer_api::BackendKind::default().into()
}
}
/// An engine is used by the store to drive the compilation and the
/// execution of a WebAssembly module.
///
/// cbindgen:ignore
#[repr(C)]
// We can let the API decide which engine is default with the given set of
// features.
//
// See the impl of `Default` for `BackendEngine` in the `wasmer` (API) crate.
#[derive(Default)]
pub struct wasm_engine_t {
pub(crate) inner: Engine,
}
#[no_mangle]
#[allow(unreachable_code)]
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
Box::new(wasm_engine_t::default())
}
/// Deletes an engine.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create a default engine.
/// wasm_engine_t* engine = wasm_engine_new();
/// int error_length = wasmer_last_error_length();
/// if (error_length > 0) {
/// char *error_message = malloc(error_length);
/// wasmer_last_error_message(error_message, error_length);
///
/// printf("Attempted to set an immutable global: `%s`\n", error_message);
/// free(error_message);
/// }
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
///
/// cbindgen:ignore
#[no_mangle]
pub unsafe extern "C" fn wasm_engine_delete(_engine: Option<Box<wasm_engine_t>>) {}
/// Creates an engine with a particular configuration.
///
/// # Example
///
/// See [`wasm_config_new`].
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_engine_new_with_config(
config: Option<Box<wasm_config_t>>,
) -> Option<Box<wasm_engine_t>> {
#[allow(unused)]
let config = *(config?);
match config.backend {
#[cfg(feature = "llvm")]
wasmer_backend_t::LLVM => config::sys::wasm_sys_engine_new_with_config(config),
#[cfg(feature = "cranelift")]
wasmer_backend_t::CRANELIFT => config::sys::wasm_sys_engine_new_with_config(config),
#[cfg(feature = "singlepass")]
wasmer_backend_t::SINGLEPASS => config::sys::wasm_sys_engine_new_with_config(config),
#[cfg(feature = "sys")]
wasmer_backend_t::HEADLESS => config::sys::wasm_sys_engine_new_with_config(config),
#[cfg(feature = "v8")]
wasmer_backend_t::V8 => config::v8::wasm_v8_engine_new_with_config(config),
#[cfg(feature = "wasmi")]
wasmer_backend_t::WASMI => config::wasmi::wasm_wasmi_engine_new_with_config(config),
#[cfg(feature = "wamr")]
wasmer_backend_t::WAMR => config::wamr::wasm_wamr_engine_new_with_config(config),
#[cfg(feature = "jsc")]
wasmer_backend_t::JSC => config::jsc::wasm_jsc_engine_new_with_config(config),
_ => unreachable!(),
}
}
/// A configuration holds the compiler and the engine used by the store.
///
/// cbindgen:ignore
#[derive(Debug, Default)]
#[repr(C)]
pub struct wasm_config_t {
pub(super) backend: wasmer_backend_t,
pub(super) backend_config: wasmer_backend_config_t,
pub(super) features: Option<Box<wasmer_features_t>>,
}
/// Create a new default Wasmer configuration.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
///
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_config_new() -> Box<wasm_config_t> {
Box::<wasm_config_t>::default()
}
/// Delete a Wasmer config object.
///
/// This function does not need to be called if `wasm_engine_new_with_config` or
/// another function that takes ownership of the `wasm_config_t` is called.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Delete the configuration
/// wasm_config_delete(config);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
/// cbindgen:ignore
#[no_mangle]
pub extern "C" fn wasm_config_delete(_config: Option<Box<wasm_config_t>>) {}
/// Updates the configuration to specify a particular engine to use.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[no_mangle]
pub extern "C" fn wasm_config_set_backend(config: &mut wasm_config_t, engine: wasmer_backend_t) {
config.backend = engine;
}
#[cfg(test)]
mod tests {
#[cfg(not(target_os = "windows"))]
use inline_c::assert_c;
#[cfg(target_os = "windows")]
use wasmer_inline_c::assert_c;
#[cfg_attr(coverage, ignore)]
#[test]
fn test_engine_new() {
(assert_c! {
#include "tests/wasmer.h"
int main() {
wasm_engine_t* engine = wasm_engine_new();
assert(engine);
wasm_engine_delete(engine);
return 0;
}
})
.success();
}
}

View File

@@ -2,58 +2,10 @@
//! `wasm_engine_t` and siblings. //! `wasm_engine_t` and siblings.
use super::{ use super::{
super::engine::{wasm_config_t, wasmer_engine_t}, super::engine::{wasm_config_t, wasmer_backend_t},
features::wasmer_features_t, features::wasmer_features_t,
}; };
#[cfg(feature = "compiler")]
use super::{super::engine::wasmer_compiler_t, target_lexicon::wasmer_target_t};
/// Unstable non-standard Wasmer-specific API to update the
/// configuration to specify a particular target for the engine.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Set the target.
/// {
/// wasmer_triple_t* triple = wasmer_triple_new_from_host();
/// wasmer_cpu_features_t* cpu_features = wasmer_cpu_features_new();
/// wasmer_target_t* target = wasmer_target_new(triple, cpu_features);
///
/// wasm_config_set_target(config, target);
/// }
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[no_mangle]
#[cfg(feature = "compiler")]
pub extern "C" fn wasm_config_set_target(config: &mut wasm_config_t, target: Box<wasmer_target_t>) {
config.target = Some(target);
}
/// Unstable non-standard Wasmer-specific API to update the /// Unstable non-standard Wasmer-specific API to update the
/// configuration to specify particular features for the engine. /// configuration to specify particular features for the engine.
/// ///
@@ -100,58 +52,6 @@ pub extern "C" fn wasm_config_set_features(
config.features = Some(features); config.features = Some(features);
} }
/// Updates the configuration to enable NaN canonicalization.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// ```rust
/// # use wasmer_inline_c::assert_c;
/// # fn main() {
/// # (assert_c! {
/// # #include "tests/wasmer.h"
/// #
/// int main() {
/// // Create the configuration.
/// wasm_config_t* config = wasm_config_new();
///
/// // Enable NaN canonicalization.
/// wasm_config_canonicalize_nans(config, true);
///
/// // Create the engine.
/// wasm_engine_t* engine = wasm_engine_new_with_config(config);
///
/// // Check we have an engine!
/// assert(engine);
///
/// // Free everything.
/// wasm_engine_delete(engine);
///
/// return 0;
/// }
/// # })
/// # .success();
/// # }
/// ```
#[no_mangle]
pub extern "C" fn wasm_config_canonicalize_nans(config: &mut wasm_config_t, enable: bool) {
config.nan_canonicalization = enable;
}
/// Check whether the given compiler is available, i.e. part of this
/// compiled library.
#[no_mangle]
#[cfg(feature = "compiler")]
pub extern "C" fn wasmer_is_compiler_available(compiler: wasmer_compiler_t) -> bool {
match compiler {
wasmer_compiler_t::CRANELIFT if cfg!(feature = "cranelift") => true,
wasmer_compiler_t::LLVM if cfg!(feature = "llvm") => true,
wasmer_compiler_t::SINGLEPASS if cfg!(feature = "singlepass") => true,
_ => false,
}
}
/// Check whether there is no compiler available in this compiled /// Check whether there is no compiler available in this compiled
/// library. /// library.
#[no_mangle] #[no_mangle]
@@ -159,11 +59,20 @@ pub extern "C" fn wasmer_is_headless() -> bool {
!cfg!(feature = "compiler") !cfg!(feature = "compiler")
} }
/// Check whether the given engine is available, i.e. part of this /// Check whether the given backend is available, i.e. part of this
/// compiled library. /// compiled library.
#[no_mangle] #[no_mangle]
pub extern "C" fn wasmer_is_engine_available(engine: wasmer_engine_t) -> bool { pub extern "C" fn wasmer_is_backend_available(backend: wasmer_backend_t) -> bool {
matches!(engine, wasmer_engine_t::UNIVERSAL if cfg!(feature = "compiler")) match backend {
wasmer_backend_t::LLVM => cfg!(feature = "llvm"),
wasmer_backend_t::CRANELIFT => cfg!(feature = "cranelift"),
wasmer_backend_t::SINGLEPASS => cfg!(feature = "singlepass"),
wasmer_backend_t::HEADLESS => cfg!(feature = "sys"),
wasmer_backend_t::V8 => cfg!(feature = "v8"),
wasmer_backend_t::WASMI => cfg!(feature = "wasmi"),
wasmer_backend_t::WAMR => cfg!(feature = "wamr"),
wasmer_backend_t::JSC => cfg!(feature = "jsc"),
}
} }
#[cfg(test)] #[cfg(test)]
@@ -197,7 +106,7 @@ mod tests {
} }
#[test] #[test]
fn test_wasmer_is_compiler_available() { fn test_wasmer_is_backend_available() {
set_var( set_var(
"CRANELIFT", "CRANELIFT",
if cfg!(feature = "cranelift") { if cfg!(feature = "cranelift") {
@@ -221,9 +130,9 @@ mod tests {
#include <stdlib.h> #include <stdlib.h>
int main() { int main() {
assert(wasmer_is_compiler_available(CRANELIFT) == (getenv("CRANELIFT")[0] == '1')); assert(wasmer_is_backend_available(CRANELIFT) == (getenv("CRANELIFT")[0] == '1'));
assert(wasmer_is_compiler_available(LLVM) == (getenv("LLVM")[0] == '1')); assert(wasmer_is_backend_available(LLVM) == (getenv("LLVM")[0] == '1'));
assert(wasmer_is_compiler_available(SINGLEPASS) == (getenv("SINGLEPASS")[0] == '1')); assert(wasmer_is_backend_available(SINGLEPASS) == (getenv("SINGLEPASS")[0] == '1'));
return 0; return 0;
} }
@@ -234,26 +143,4 @@ mod tests {
remove_var("LLVM"); remove_var("LLVM");
remove_var("SINGLEPASS"); remove_var("SINGLEPASS");
} }
#[test]
fn test_wasmer_is_engine_available() {
set_var(
"UNIVERSAL",
if cfg!(feature = "compiler") { "1" } else { "0" },
);
(assert_c! {
#include "tests/wasmer.h"
#include <stdlib.h>
int main() {
assert(wasmer_is_engine_available(UNIVERSAL) == (getenv("UNIVERSAL")[0] == '1'));
return 0;
}
})
.success();
remove_var("UNIVERSAL");
}
} }

View File

@@ -3,7 +3,6 @@
pub mod metering; pub mod metering;
use super::super::engine::wasm_config_t;
use std::sync::Arc; use std::sync::Arc;
use wasmer_api::sys::ModuleMiddleware; use wasmer_api::sys::ModuleMiddleware;
@@ -21,20 +20,3 @@ compile_error!("The `middlewares` feature requires the `compiler` feature to be
pub struct wasmer_middleware_t { pub struct wasmer_middleware_t {
pub(in crate::wasm_c_api) inner: Arc<dyn ModuleMiddleware>, pub(in crate::wasm_c_api) inner: Arc<dyn ModuleMiddleware>,
} }
/// Updates the configuration to add a module middleware.
///
/// This function takes ownership of `middleware`.
///
/// This is a Wasmer-specific function.
///
/// # Example
///
/// See the documentation of the [`metering`] module.
#[no_mangle]
pub extern "C" fn wasm_config_push_middleware(
config: &mut wasm_config_t,
middleware: Box<wasmer_middleware_t>,
) {
config.middlewares.push(*middleware);
}

View File

@@ -5,7 +5,6 @@ pub mod middlewares;
pub mod module; pub mod module;
#[cfg(feature = "compiler")] #[cfg(feature = "compiler")]
pub mod parser; pub mod parser;
#[cfg(any(feature = "compiler", feature = "compiler-headless"))]
pub mod target_lexicon; pub mod target_lexicon;
#[cfg(feature = "wasi")] #[cfg(feature = "wasi")]
pub mod wasi; pub mod wasi;

View File

@@ -172,7 +172,7 @@ pub unsafe extern "C" fn wasmer_module_new(
engine: Option<&mut wasm_engine_t>, engine: Option<&mut wasm_engine_t>,
bytes: Option<&wasm_byte_vec_t>, bytes: Option<&wasm_byte_vec_t>,
) -> Option<Box<wasm_module_t>> { ) -> Option<Box<wasm_module_t>> {
let engine: wasmer_api::Engine = engine?.inner.clone().into(); let engine: wasmer_api::Engine = engine?.inner.clone();
let bytes = bytes?; let bytes = bytes?;
let module = c_try!(Module::from_binary(&engine, bytes.as_slice())); let module = c_try!(Module::from_binary(&engine, bytes.as_slice()));

View File

@@ -57,7 +57,7 @@ use super::super::types::wasm_name_t;
use enumset::EnumSet; use enumset::EnumSet;
use std::slice; use std::slice;
use std::str::{self, FromStr}; use std::str::{self, FromStr};
use wasmer_api::sys::{CpuFeature, Target, Triple}; use wasmer_types::target::{CpuFeature, Target, Triple};
/// Unstable non-standard Wasmer-specific API to represent a triple + /// Unstable non-standard Wasmer-specific API to represent a triple +
/// CPU features pair. /// CPU features pair.

View File

@@ -16,30 +16,36 @@
wasm_engine_t *wasm_engine_new() { wasm_engine_t *wasm_engine_new() {
wasm_config_t *config = wasm_config_new(); wasm_config_t *config = wasm_config_new();
char *wasmer_test_compiler = getenv("WASMER_CAPI_CONFIG"); char *wasmer_test_backend = getenv("WASMER_CAPI_CONFIG");
char *wasmer_test_engine; char *wasmer_test_engine;
strtok_r(wasmer_test_compiler, "-", &wasmer_test_engine); printf("Using backend: %s\n", wasmer_test_backend);
printf("Using compiler: %s, engine: %s\n", wasmer_test_compiler,
wasmer_test_engine); strtok_r(wasmer_test_backend, "-", &wasmer_test_engine);
if (strcmp(wasmer_test_compiler, "cranelift") == 0) {
assert(wasmer_is_compiler_available(CRANELIFT)); if (strcmp(wasmer_test_backend, "cranelift") == 0) {
wasm_config_set_compiler(config, CRANELIFT); assert(wasmer_is_backend_available(CRANELIFT));
} else if (strcmp(wasmer_test_compiler, "llvm") == 0) { wasm_config_set_backend(config, CRANELIFT);
assert(wasmer_is_compiler_available(LLVM)); } else if (strcmp(wasmer_test_backend, "llvm") == 0) {
wasm_config_set_compiler(config, LLVM); assert(wasmer_is_backend_available(LLVM));
} else if (strcmp(wasmer_test_compiler, "singlepass") == 0) { wasm_config_set_backend(config, LLVM);
assert(wasmer_is_compiler_available(SINGLEPASS)); } else if (strcmp(wasmer_test_backend, "singlepass") == 0) {
wasm_config_set_compiler(config, SINGLEPASS); assert(wasmer_is_backend_available(SINGLEPASS));
} else if (wasmer_test_compiler) { wasm_config_set_backend(config, SINGLEPASS);
printf("Compiler %s not recognized\n", wasmer_test_compiler); } else if (strcmp(wasmer_test_backend, "headless") == 0) {
abort(); assert(wasmer_is_backend_available(HEADLESS));
} wasm_config_set_backend(config, HEADLESS);
if (strcmp(wasmer_test_engine, "universal") == 0) { } else if (strcmp(wasmer_test_backend, "v8") == 0) {
assert(wasmer_is_engine_available(UNIVERSAL)); assert(wasmer_is_backend_available(V8));
wasm_config_set_engine(config, UNIVERSAL); wasm_config_set_backend(config, V8);
} else if (wasmer_test_engine) { } else if (strcmp(wasmer_test_backend, "wamr") == 0) {
printf("Engine %s not recognized\n", wasmer_test_engine); assert(wasmer_is_backend_available(WAMR));
wasm_config_set_backend(config, WAMR);
} else if (strcmp(wasmer_test_backend, "wasmi") == 0) {
assert(wasmer_is_backend_available(WASMI));
wasm_config_set_backend(config, WASMI);
} else if (wasmer_test_backend) {
printf("Compiler %s not recognized\n", wasmer_test_backend);
abort(); abort();
} }