mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-08 05:38:19 +00:00
1826 lines
52 KiB
Rust
1826 lines
52 KiB
Rust
//! entrypoints for the standard C API
|
|
|
|
use std::convert::{TryFrom, TryInto};
|
|
use std::ffi::c_void;
|
|
use std::mem;
|
|
use std::ptr::{self, NonNull};
|
|
use std::slice;
|
|
use std::sync::Arc;
|
|
|
|
#[cfg(feature = "engine")]
|
|
use wasmer::Tunables;
|
|
use wasmer::{
|
|
Engine, ExportType, Extern, ExternType, Features, Function, FunctionType, Global, GlobalType,
|
|
Instance, Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store,
|
|
Table, TableType, Val, ValType,
|
|
};
|
|
#[cfg(feature = "jit")]
|
|
use wasmer_engine_jit::JITEngine;
|
|
|
|
use crate::error::update_last_error;
|
|
|
|
macro_rules! c_try {
|
|
($expr:expr) => {{
|
|
let res: Result<_, _> = $expr;
|
|
match res {
|
|
Ok(val) => val,
|
|
Err(err) => {
|
|
update_last_error(err);
|
|
return None;
|
|
}
|
|
}
|
|
}};
|
|
($expr:expr, $e:expr) => {{
|
|
let opt: Option<_> = $expr;
|
|
c_try!(opt.ok_or_else(|| $e))
|
|
}};
|
|
}
|
|
|
|
/// this can be a wasmer-specific type with wasmer-specific functions for manipulating it
|
|
#[repr(C)]
|
|
pub struct wasm_config_t {}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_config_new() -> *mut wasm_config_t {
|
|
todo!("wasm_config_new")
|
|
//ptr::null_mut()
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_engine_t {
|
|
pub(crate) inner: Box<dyn Engine + Send + Sync>,
|
|
}
|
|
|
|
cfg_if! {
|
|
if #[cfg(all(feature = "jit", feature = "compiler"))] {
|
|
// Compiler JIT
|
|
use wasmer_compiler::CompilerConfig;
|
|
fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
|
|
cfg_if! {
|
|
if #[cfg(feature = "cranelift")] {
|
|
Box::new(wasmer_compiler_cranelift::CraneliftConfig::default())
|
|
} else if #[cfg(feature = "llvm")] {
|
|
Box::new(wasmer_compiler_llvm::LLVMConfig::default())
|
|
} else if #[cfg(feature = "singlepass")] {
|
|
Box::new(wasmer_compiler_singlepass::SinglepassConfig::default())
|
|
} else {
|
|
compile_error!("Please enable one of the compiler backends")
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
|
let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
|
|
let tunables = Tunables::default();
|
|
let features = Features::default();
|
|
let engine: Box<dyn Engine + Send + Sync> = Box::new(JITEngine::new(compiler_config, tunables, features));
|
|
Box::new(wasm_engine_t { inner: engine })
|
|
}
|
|
}
|
|
else if #[cfg(feature = "jit")] {
|
|
// Headless JIT
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
|
let tunables = Tunables::default();
|
|
let engine: Box<dyn Engine + Send + Sync> = Arc::new(JITEngine::headless(tunables));
|
|
Box::new(wasm_engine_t { inner: engine })
|
|
}
|
|
}
|
|
else {
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
|
unimplemented!("The JITEngine is not attached");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_engine_delete(_wasm_engine_address: Option<Box<wasm_engine_t>>) {}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_engine_new_with_config(
|
|
_config_ptr: *mut wasm_config_t,
|
|
) -> Box<wasm_engine_t> {
|
|
wasm_engine_new()
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_instance_t {
|
|
inner: Arc<Instance>,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_instance_new(
|
|
store: Option<NonNull<wasm_store_t>>,
|
|
module: &wasm_module_t,
|
|
imports: *const *const wasm_extern_t,
|
|
// own
|
|
_traps: *mut *mut wasm_trap_t,
|
|
) -> Option<Box<wasm_instance_t>> {
|
|
let wasm_module = &module.inner;
|
|
let module_imports = wasm_module.imports();
|
|
let module_import_count = module_imports.len();
|
|
let imports = argument_import_iter(imports);
|
|
let resolver: OrderedResolver = imports
|
|
.map(|imp| &imp.inner)
|
|
.take(module_import_count)
|
|
.cloned()
|
|
.collect();
|
|
|
|
let instance = Arc::new(c_try!(Instance::new(wasm_module, &resolver)));
|
|
Some(Box::new(wasm_instance_t { inner: instance }))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_instance_delete(_instance: Option<Box<wasm_instance_t>>) {}
|
|
|
|
struct CArrayIter<T: Sized + 'static> {
|
|
cur_entry: *const *const T,
|
|
}
|
|
|
|
impl<T: Sized + 'static> CArrayIter<T> {
|
|
fn new(array: *const *const T) -> Option<Self> {
|
|
if array.is_null() {
|
|
None
|
|
} else {
|
|
Some(CArrayIter { cur_entry: array })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Sized + 'static> Iterator for CArrayIter<T> {
|
|
type Item = &'static T;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next_entry_candidate = unsafe { *self.cur_entry };
|
|
if next_entry_candidate.is_null() {
|
|
None
|
|
} else {
|
|
self.cur_entry = unsafe { self.cur_entry.add(1) };
|
|
Some(unsafe { &*next_entry_candidate })
|
|
}
|
|
}
|
|
}
|
|
|
|
// reads from null-terminated array of `wasm_extern_t`s
|
|
unsafe fn argument_import_iter(
|
|
imports: *const *const wasm_extern_t,
|
|
) -> Box<dyn Iterator<Item = &'static wasm_extern_t>> {
|
|
CArrayIter::new(imports)
|
|
.map(|it| Box::new(it) as _)
|
|
.unwrap_or_else(|| Box::new(std::iter::empty()) as _)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_instance_exports(
|
|
instance: &wasm_instance_t,
|
|
// TODO: review types on wasm_declare_vec, handle the optional pointer part properly
|
|
out: &mut wasm_extern_vec_t,
|
|
) {
|
|
let instance = &instance.inner;
|
|
let mut extern_vec = instance
|
|
.exports
|
|
.iter()
|
|
.map(|(name, r#extern)| {
|
|
let function = if let Extern::Function { .. } = r#extern {
|
|
instance.exports.get_function(&name).ok().cloned()
|
|
} else {
|
|
None
|
|
};
|
|
Box::into_raw(Box::new(wasm_extern_t {
|
|
instance: Some(Arc::clone(instance)),
|
|
inner: r#extern.clone(),
|
|
}))
|
|
})
|
|
.collect::<Vec<*mut wasm_extern_t>>();
|
|
extern_vec.shrink_to_fit();
|
|
|
|
out.size = extern_vec.len();
|
|
out.data = extern_vec.as_mut_ptr();
|
|
// TODO: double check that the destructor will work correctly here
|
|
mem::forget(extern_vec);
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_module_t {
|
|
inner: Arc<Module>,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_module_new(
|
|
store_ptr: Option<NonNull<wasm_store_t>>,
|
|
bytes: &wasm_byte_vec_t,
|
|
) -> Option<Box<wasm_module_t>> {
|
|
// TODO: review lifetime of byte slice
|
|
let wasm_byte_slice: &[u8] = slice::from_raw_parts_mut(bytes.data, bytes.size);
|
|
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
let module = c_try!(Module::from_binary(store, wasm_byte_slice));
|
|
|
|
Some(Box::new(wasm_module_t {
|
|
inner: Arc::new(module),
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_module_delete(_module: Option<Box<wasm_module_t>>) {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_module_exports(
|
|
module: &wasm_module_t,
|
|
out: &mut wasm_exporttype_vec_t,
|
|
) {
|
|
let mut exports = module
|
|
.inner
|
|
.exports()
|
|
.map(Into::into)
|
|
.map(Box::new)
|
|
.map(Box::into_raw)
|
|
.collect::<Vec<*mut wasm_exporttype_t>>();
|
|
|
|
debug_assert_eq!(exports.len(), exports.capacity());
|
|
out.size = exports.len();
|
|
out.data = exports.as_mut_ptr();
|
|
mem::forget(exports);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_module_deserialize(
|
|
store_ptr: Option<NonNull<wasm_store_t>>,
|
|
bytes: *const wasm_byte_vec_t,
|
|
) -> Option<NonNull<wasm_module_t>> {
|
|
// TODO: read config from store and use that to decide which compiler to use
|
|
|
|
let byte_slice = if bytes.is_null() || (&*bytes).into_slice().is_none() {
|
|
// TODO: error handling here
|
|
return None;
|
|
} else {
|
|
(&*bytes).into_slice().unwrap()
|
|
};
|
|
|
|
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
let module = c_try!(Module::deserialize(store, byte_slice));
|
|
|
|
Some(NonNull::new_unchecked(Box::into_raw(Box::new(
|
|
wasm_module_t {
|
|
inner: Arc::new(module),
|
|
},
|
|
))))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_module_serialize(
|
|
module: &wasm_module_t,
|
|
out_ptr: &mut wasm_byte_vec_t,
|
|
) {
|
|
let mut byte_vec = match module.inner.serialize() {
|
|
Ok(mut byte_vec) => {
|
|
byte_vec.shrink_to_fit();
|
|
byte_vec
|
|
}
|
|
Err(_) => return,
|
|
};
|
|
// ensure we won't leak memory
|
|
// TODO: use `Vec::into_raw_parts` when it becomes stable
|
|
debug_assert_eq!(byte_vec.capacity(), byte_vec.len());
|
|
out_ptr.size = byte_vec.len();
|
|
out_ptr.data = byte_vec.as_mut_ptr();
|
|
mem::forget(byte_vec);
|
|
}
|
|
|
|
/// Opaque wrapper around `Store`
|
|
#[repr(C)]
|
|
pub struct wasm_store_t {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_store_new(
|
|
wasm_engine_ptr: Option<NonNull<wasm_engine_t>>,
|
|
) -> Option<NonNull<wasm_store_t>> {
|
|
let wasm_engine_ptr = wasm_engine_ptr?;
|
|
let wasm_engine = wasm_engine_ptr.as_ref();
|
|
let store = Store::new(&*wasm_engine.inner);
|
|
Some(NonNull::new_unchecked(
|
|
Box::into_raw(Box::new(store)) as *mut wasm_store_t
|
|
))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_store_delete(wasm_store: Option<NonNull<wasm_store_t>>) {
|
|
if let Some(s_inner) = wasm_store {
|
|
// this should not leak memory:
|
|
// we should double check it to make sure though
|
|
let _: Box<Store> = Box::from_raw(s_inner.cast::<Store>().as_ptr());
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_as_extern(
|
|
func_ptr: Option<NonNull<wasm_func_t>>,
|
|
) -> Option<Box<wasm_extern_t>> {
|
|
let func_ptr = func_ptr?;
|
|
let func = func_ptr.as_ref();
|
|
|
|
Some(Box::new(wasm_extern_t {
|
|
instance: func.instance.clone(),
|
|
inner: Extern::Function(func.inner.clone()),
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_global_as_extern(
|
|
global_ptr: Option<NonNull<wasm_global_t>>,
|
|
) -> Option<Box<wasm_extern_t>> {
|
|
let global_ptr = global_ptr?;
|
|
let global = global_ptr.as_ref();
|
|
|
|
Some(Box::new(wasm_extern_t {
|
|
// update this if global does hold onto an `instance`
|
|
instance: None,
|
|
inner: Extern::Global(global.inner.clone()),
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_as_extern(
|
|
memory_ptr: Option<NonNull<wasm_memory_t>>,
|
|
) -> Option<Box<wasm_extern_t>> {
|
|
let memory_ptr = memory_ptr?;
|
|
let memory = memory_ptr.as_ref();
|
|
|
|
Some(Box::new(wasm_extern_t {
|
|
// update this if global does hold onto an `instance`
|
|
instance: None,
|
|
inner: Extern::Memory(memory.inner.clone()),
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_as_extern(
|
|
table_ptr: Option<NonNull<wasm_table_t>>,
|
|
) -> Option<Box<wasm_extern_t>> {
|
|
let table_ptr = table_ptr?;
|
|
let table = table_ptr.as_ref();
|
|
|
|
Some(Box::new(wasm_extern_t {
|
|
// update this if global does hold onto an `instance`
|
|
instance: None,
|
|
inner: Extern::Table(table.inner.clone()),
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_extern_as_func(
|
|
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
|
) -> Option<Box<wasm_func_t>> {
|
|
let extern_ptr = extern_ptr?;
|
|
let r#extern = extern_ptr.as_ref();
|
|
if let Extern::Function(f) = &r#extern.inner {
|
|
Some(Box::new(wasm_func_t {
|
|
inner: f.clone(),
|
|
instance: r#extern.instance.clone(),
|
|
}))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_extern_as_global(
|
|
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
|
) -> Option<Box<wasm_global_t>> {
|
|
let extern_ptr = extern_ptr?;
|
|
let r#extern = extern_ptr.as_ref();
|
|
if let Extern::Global(g) = &r#extern.inner {
|
|
Some(Box::new(wasm_global_t { inner: g.clone() }))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_extern_as_memory(
|
|
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
|
) -> Option<Box<wasm_memory_t>> {
|
|
let extern_ptr = extern_ptr?;
|
|
let r#extern = extern_ptr.as_ref();
|
|
if let Extern::Memory(m) = &r#extern.inner {
|
|
Some(Box::new(wasm_memory_t { inner: m.clone() }))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_extern_as_table(
|
|
extern_ptr: Option<NonNull<wasm_extern_t>>,
|
|
) -> Option<Box<wasm_table_t>> {
|
|
let extern_ptr = extern_ptr?;
|
|
let r#extern = extern_ptr.as_ref();
|
|
if let Extern::Table(t) = &r#extern.inner {
|
|
Some(Box::new(wasm_table_t { inner: t.clone() }))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_table_size_t = u32;
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_mutability_t = u8;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(u8)]
|
|
enum wasm_mutability_enum {
|
|
WASM_CONST = 0,
|
|
WASM_VAR,
|
|
}
|
|
|
|
impl wasm_mutability_enum {
|
|
#[allow(dead_code)]
|
|
fn is_mutable(self) -> bool {
|
|
self == Self::WASM_VAR
|
|
}
|
|
}
|
|
|
|
impl TryFrom<wasm_mutability_t> for wasm_mutability_enum {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: wasm_mutability_t) -> Result<Self, Self::Error> {
|
|
Ok(match item {
|
|
0 => wasm_mutability_enum::WASM_CONST,
|
|
1 => wasm_mutability_enum::WASM_VAR,
|
|
_ => return Err("wasm_mutability_t value out of bounds"),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<wasm_mutability_enum> for wasm_mutability_t {
|
|
fn from(other: wasm_mutability_enum) -> Self {
|
|
other as wasm_mutability_t
|
|
}
|
|
}
|
|
|
|
impl From<wasm_mutability_enum> for Mutability {
|
|
fn from(other: wasm_mutability_enum) -> Self {
|
|
match other {
|
|
wasm_mutability_enum::WASM_CONST => Mutability::Const,
|
|
wasm_mutability_enum::WASM_VAR => Mutability::Var,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Mutability> for wasm_mutability_enum {
|
|
fn from(other: Mutability) -> Self {
|
|
match other {
|
|
Mutability::Const => wasm_mutability_enum::WASM_CONST,
|
|
Mutability::Var => wasm_mutability_enum::WASM_VAR,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_valkind_t = u8;
|
|
|
|
impl From<wasm_valkind_enum> for ValType {
|
|
fn from(other: wasm_valkind_enum) -> Self {
|
|
use wasm_valkind_enum::*;
|
|
match other {
|
|
WASM_I32 => ValType::I32,
|
|
WASM_I64 => ValType::I64,
|
|
WASM_F32 => ValType::F32,
|
|
WASM_F64 => ValType::F64,
|
|
WASM_ANYREF => ValType::ExternRef,
|
|
WASM_FUNCREF => ValType::FuncRef,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<wasm_valtype_t> for ValType {
|
|
fn from(other: wasm_valtype_t) -> Self {
|
|
other.valkind.into()
|
|
}
|
|
}
|
|
|
|
impl From<ValType> for wasm_valtype_t {
|
|
fn from(other: ValType) -> Self {
|
|
Self {
|
|
valkind: other.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(u8)]
|
|
pub enum wasm_valkind_enum {
|
|
WASM_I32 = 0,
|
|
WASM_I64 = 1,
|
|
WASM_F32 = 2,
|
|
WASM_F64 = 3,
|
|
WASM_ANYREF = 128,
|
|
WASM_FUNCREF = 129,
|
|
}
|
|
|
|
impl From<ValType> for wasm_valkind_enum {
|
|
fn from(other: ValType) -> Self {
|
|
match other {
|
|
ValType::I32 => Self::WASM_I32,
|
|
ValType::I64 => Self::WASM_I64,
|
|
ValType::F32 => Self::WASM_F32,
|
|
ValType::F64 => Self::WASM_F64,
|
|
ValType::V128 => todo!("no v128 type in Wasm C API yet!"),
|
|
ValType::ExternRef => Self::WASM_ANYREF,
|
|
ValType::FuncRef => Self::WASM_FUNCREF,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy)]
|
|
pub union wasm_val_inner {
|
|
int32_t: i32,
|
|
int64_t: i64,
|
|
float32_t: f32,
|
|
float64_t: f64,
|
|
wref: *mut wasm_ref_t,
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_val_t {
|
|
kind: wasm_valkind_t,
|
|
of: wasm_val_inner,
|
|
}
|
|
|
|
impl Clone for wasm_val_t {
|
|
fn clone(&self) -> Self {
|
|
wasm_val_t {
|
|
kind: self.kind,
|
|
of: self.of.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_val_copy(out_ptr: *mut wasm_val_t, val: &wasm_val_t) {
|
|
(*out_ptr).kind = val.kind;
|
|
(*out_ptr).of =
|
|
// TODO: handle this error
|
|
match val.kind.try_into().unwrap() {
|
|
wasm_valkind_enum::WASM_I32 => wasm_val_inner { int32_t: val.of.int32_t },
|
|
wasm_valkind_enum::WASM_I64 => wasm_val_inner { int64_t: val.of.int64_t },
|
|
wasm_valkind_enum::WASM_F32 => wasm_val_inner { float32_t: val.of.float32_t },
|
|
wasm_valkind_enum::WASM_F64 => wasm_val_inner { float64_t: val.of.float64_t },
|
|
wasm_valkind_enum::WASM_ANYREF => wasm_val_inner { wref: val.of.wref },
|
|
wasm_valkind_enum::WASM_FUNCREF => wasm_val_inner { wref: val.of.wref },
|
|
};
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_val_delete(val: Option<NonNull<wasm_val_t>>) {
|
|
if let Some(v_inner) = val {
|
|
// TODO: figure out where wasm_val is allocated first...
|
|
let _ = Box::from_raw(v_inner.as_ptr());
|
|
}
|
|
}
|
|
|
|
impl TryFrom<wasm_valkind_t> for wasm_valkind_enum {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: wasm_valkind_t) -> Result<Self, Self::Error> {
|
|
Ok(match item {
|
|
0 => wasm_valkind_enum::WASM_I32,
|
|
1 => wasm_valkind_enum::WASM_I64,
|
|
2 => wasm_valkind_enum::WASM_F32,
|
|
3 => wasm_valkind_enum::WASM_F64,
|
|
128 => wasm_valkind_enum::WASM_ANYREF,
|
|
129 => wasm_valkind_enum::WASM_FUNCREF,
|
|
_ => return Err("valkind value out of bounds"),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl TryFrom<wasm_val_t> for Val {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: wasm_val_t) -> Result<Self, Self::Error> {
|
|
(&item).try_into()
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&wasm_val_t> for Val {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: &wasm_val_t) -> Result<Self, Self::Error> {
|
|
Ok(match item.kind.try_into()? {
|
|
wasm_valkind_enum::WASM_I32 => Val::I32(unsafe { item.of.int32_t }),
|
|
wasm_valkind_enum::WASM_I64 => Val::I64(unsafe { item.of.int64_t }),
|
|
wasm_valkind_enum::WASM_F32 => Val::F32(unsafe { item.of.float32_t }),
|
|
wasm_valkind_enum::WASM_F64 => Val::F64(unsafe { item.of.float64_t }),
|
|
wasm_valkind_enum::WASM_ANYREF => return Err("ANYREF not supported at this time"),
|
|
wasm_valkind_enum::WASM_FUNCREF => return Err("FUNCREF not supported at this time"),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl TryFrom<Val> for wasm_val_t {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: Val) -> Result<Self, Self::Error> {
|
|
wasm_val_t::try_from(&item)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Val> for wasm_val_t {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: &Val) -> Result<Self, Self::Error> {
|
|
Ok(match *item {
|
|
Val::I32(v) => wasm_val_t {
|
|
of: wasm_val_inner { int32_t: v },
|
|
kind: wasm_valkind_enum::WASM_I32 as _,
|
|
},
|
|
Val::I64(v) => wasm_val_t {
|
|
of: wasm_val_inner { int64_t: v },
|
|
kind: wasm_valkind_enum::WASM_I64 as _,
|
|
},
|
|
Val::F32(v) => wasm_val_t {
|
|
of: wasm_val_inner { float32_t: v },
|
|
kind: wasm_valkind_enum::WASM_F32 as _,
|
|
},
|
|
Val::F64(v) => wasm_val_t {
|
|
of: wasm_val_inner { float64_t: v },
|
|
kind: wasm_valkind_enum::WASM_F64 as _,
|
|
},
|
|
Val::V128(_) => return Err("128bit SIMD types not yet supported in Wasm C API"),
|
|
_ => todo!("Handle these values in TryFrom<Val> for wasm_val_t"),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_func_callback_t =
|
|
unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t;
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
|
|
*mut c_void,
|
|
args: *const wasm_val_t,
|
|
results: *mut wasm_val_t,
|
|
) -> *mut wasm_trap_t;
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_func_t {
|
|
inner: Function,
|
|
// this is how we ensure the instance stays alive
|
|
instance: Option<Arc<Instance>>,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_new(
|
|
store: Option<NonNull<wasm_store_t>>,
|
|
ft: &wasm_functype_t,
|
|
callback: wasm_func_callback_t,
|
|
) -> Option<Box<wasm_func_t>> {
|
|
// TODO: handle null pointers?
|
|
let store_ptr = store?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
let func_sig = ft.sig();
|
|
let num_rets = func_sig.results().len();
|
|
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
|
let processed_args = args
|
|
.into_iter()
|
|
.map(TryInto::try_into)
|
|
.collect::<Result<Vec<wasm_val_t>, _>>()
|
|
.expect("Argument conversion failed");
|
|
|
|
let mut results = vec![
|
|
wasm_val_t {
|
|
kind: wasm_valkind_enum::WASM_I64 as _,
|
|
of: wasm_val_inner { int64_t: 0 },
|
|
};
|
|
num_rets
|
|
];
|
|
|
|
let _traps = callback(processed_args.as_ptr(), results.as_mut_ptr());
|
|
// TODO: do something with `traps`
|
|
|
|
let processed_results = results
|
|
.into_iter()
|
|
.map(TryInto::try_into)
|
|
.collect::<Result<Vec<Val>, _>>()
|
|
.expect("Result conversion failed");
|
|
Ok(processed_results)
|
|
};
|
|
let f = Function::new_dynamic(store, &func_sig, inner_callback);
|
|
Some(Box::new(wasm_func_t {
|
|
instance: None,
|
|
inner: f,
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_new_with_env(
|
|
store: Option<NonNull<wasm_store_t>>,
|
|
ft: &wasm_functype_t,
|
|
callback: wasm_func_callback_with_env_t,
|
|
env: *mut c_void,
|
|
finalizer: wasm_env_finalizer_t,
|
|
) -> Option<Box<wasm_func_t>> {
|
|
// TODO: handle null pointers?
|
|
let store_ptr = store?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
let func_sig = ft.sig();
|
|
let num_rets = func_sig.results().len();
|
|
let inner_callback =
|
|
move |env: &mut *mut c_void, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
|
let processed_args = args
|
|
.into_iter()
|
|
.map(TryInto::try_into)
|
|
.collect::<Result<Vec<wasm_val_t>, _>>()
|
|
.expect("Argument conversion failed");
|
|
|
|
let mut results = vec![
|
|
wasm_val_t {
|
|
kind: wasm_valkind_enum::WASM_I64 as _,
|
|
of: wasm_val_inner { int64_t: 0 },
|
|
};
|
|
num_rets
|
|
];
|
|
|
|
let _traps = callback(*env, processed_args.as_ptr(), results.as_mut_ptr());
|
|
// TODO: do something with `traps`
|
|
|
|
let processed_results = results
|
|
.into_iter()
|
|
.map(TryInto::try_into)
|
|
.collect::<Result<Vec<Val>, _>>()
|
|
.expect("Result conversion failed");
|
|
Ok(processed_results)
|
|
};
|
|
let f = Function::new_dynamic_env(store, &func_sig, env, inner_callback);
|
|
Some(Box::new(wasm_func_t {
|
|
instance: None,
|
|
inner: f,
|
|
}))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_call(
|
|
func: &wasm_func_t,
|
|
args: *const wasm_val_t,
|
|
results: *mut wasm_val_t,
|
|
) -> Option<NonNull<wasm_trap_t>> {
|
|
let num_params = func.inner.ty().params().len();
|
|
let params: Vec<Val> = (0..num_params)
|
|
.map(|i| (&(*args.add(i))).try_into())
|
|
.collect::<Result<_, _>>()
|
|
.ok()?;
|
|
|
|
match func.inner.call(¶ms) {
|
|
Ok(wasm_results) => {
|
|
for (i, actual_result) in wasm_results.iter().enumerate() {
|
|
let result_loc = &mut (*results.add(i));
|
|
*result_loc = (&*actual_result).try_into().ok()?;
|
|
}
|
|
None
|
|
}
|
|
Err(e) => Some(NonNull::new_unchecked(Box::into_raw(Box::new(e)) as _)),
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize {
|
|
func.inner.ty().params().len()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
|
|
func.inner.ty().results().len()
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_global_t {
|
|
// maybe needs to hold onto instance
|
|
inner: Global,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_global_new(
|
|
store_ptr: Option<NonNull<wasm_store_t>>,
|
|
gt: &wasm_globaltype_t,
|
|
val: &wasm_val_t,
|
|
) -> Option<Box<wasm_global_t>> {
|
|
let gt = gt.as_globaltype();
|
|
let wasm_val = val.try_into().ok()?;
|
|
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
let global = if gt.mutability.is_mutable() {
|
|
Global::new_mut(store, wasm_val)
|
|
} else {
|
|
Global::new(store, wasm_val)
|
|
};
|
|
|
|
Some(Box::new(wasm_global_t { inner: global }))
|
|
}
|
|
|
|
#[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(wasm_global: &wasm_global_t) -> Box<wasm_global_t> {
|
|
// do shallow copy
|
|
Box::new(wasm_global_t {
|
|
inner: wasm_global.inner.clone(),
|
|
})
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_global_get(wasm_global: &wasm_global_t, out: &mut wasm_val_t) {
|
|
let value = wasm_global.inner.get();
|
|
*out = value.try_into().unwrap();
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_global_set(wasm_global: &mut wasm_global_t, val: &wasm_val_t) {
|
|
let value: Val = val.try_into().unwrap();
|
|
wasm_global.inner.set(value);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_global_same(
|
|
wasm_global1: &wasm_global_t,
|
|
wasm_global2: &wasm_global_t,
|
|
) -> bool {
|
|
wasm_global1.inner.same(&wasm_global2.inner)
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_memory_t {
|
|
// maybe needs to hold onto instance
|
|
inner: Memory,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_new(
|
|
store_ptr: Option<NonNull<wasm_store_t>>,
|
|
mt: &wasm_memorytype_t,
|
|
) -> Option<Box<wasm_memory_t>> {
|
|
let md = mt.as_memorytype().clone();
|
|
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
|
|
let memory = c_try!(Memory::new(store, md));
|
|
Some(Box::new(wasm_memory_t { inner: memory }))
|
|
}
|
|
|
|
#[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(wasm_memory: &wasm_memory_t) -> Box<wasm_memory_t> {
|
|
// do shallow copy
|
|
Box::new(wasm_memory_t {
|
|
inner: wasm_memory.inner.clone(),
|
|
})
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_type(_memory_ptr: &wasm_memory_t) -> *mut wasm_memorytype_t {
|
|
todo!("wasm_memory_type")
|
|
}
|
|
|
|
// get a raw pointer into bytes
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_data(memory: &mut wasm_memory_t) -> *mut u8 {
|
|
mem::transmute::<&[std::cell::Cell<u8>], &[u8]>(&memory.inner.view()[..]) as *const [u8]
|
|
as *const u8 as *mut u8
|
|
}
|
|
|
|
// size in bytes
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_data_size(memory: &wasm_memory_t) -> usize {
|
|
memory.inner.size().bytes().0
|
|
}
|
|
|
|
// size in pages
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_size(memory: &wasm_memory_t) -> u32 {
|
|
memory.inner.size().0 as _
|
|
}
|
|
|
|
// delta is in pages
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_grow(memory: &mut wasm_memory_t, delta: u32) -> bool {
|
|
memory.inner.grow(Pages(delta)).is_ok()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memory_same(
|
|
wasm_memory1: &wasm_memory_t,
|
|
wasm_memory2: &wasm_memory_t,
|
|
) -> bool {
|
|
wasm_memory1.inner.same(&wasm_memory2.inner)
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_table_t {
|
|
// maybe needs to hold onto instance
|
|
inner: Table,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_new(
|
|
store_ptr: Option<NonNull<wasm_store_t>>,
|
|
tt: &wasm_tabletype_t,
|
|
init: *const wasm_ref_t,
|
|
) -> Option<Box<wasm_table_t>> {
|
|
let tt = tt.as_tabletype().clone();
|
|
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
|
|
let store = store_ptr.as_ref();
|
|
|
|
let init_val = todo!("get val from init somehow");
|
|
|
|
let table = c_try!(Table::new(store, tt, init_val));
|
|
Some(Box::new(wasm_table_t { inner: table }))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_delete(_table: Option<Box<wasm_table_t>>) {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_copy(wasm_table: &wasm_table_t) -> Box<wasm_table_t> {
|
|
// do shallow copy
|
|
Box::new(wasm_table_t {
|
|
inner: wasm_table.inner.clone(),
|
|
})
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_same(
|
|
wasm_table1: &wasm_table_t,
|
|
wasm_table2: &wasm_table_t,
|
|
) -> bool {
|
|
wasm_table1.inner.same(&wasm_table2.inner)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_size(wasm_table: &wasm_table_t) -> usize {
|
|
wasm_table.inner.size() as _
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_table_grow(
|
|
_wasm_table: &mut wasm_table_t,
|
|
_delta: wasm_table_size_t,
|
|
_init: *mut wasm_ref_t,
|
|
) -> bool {
|
|
// TODO: maybe need to look at result to return `true`; also maybe report error here
|
|
//wasm_table.inner.grow(delta, init).is_ok()
|
|
todo!("Blocked on transforming ExternRef into a val type")
|
|
}
|
|
|
|
macro_rules! wasm_declare_own {
|
|
($name:ident) => {
|
|
paste::item! {
|
|
#[repr(C)]
|
|
pub struct [<wasm_ $name _t>] {}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn [<wasm_ $name _delete>](_arg: *mut [<wasm_ $name _t>]) {
|
|
todo!("in generated delete")
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
macro_rules! wasm_declare_vec_inner {
|
|
($name:ident) => {
|
|
paste::item! {
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn [<wasm_ $name _vec_new_empty>](out: *mut [<wasm_ $name _vec_t>]) {
|
|
// TODO: actually implement this
|
|
[<wasm_ $name _vec_new_uninitialized>](out, 0);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: *mut [<wasm_ $name _vec_t>]) {
|
|
let vec = &mut *ptr;
|
|
if !vec.data.is_null() {
|
|
Vec::from_raw_parts(vec.data, vec.size, vec.size);
|
|
vec.data = ptr::null_mut();
|
|
vec.size = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! wasm_declare_vec {
|
|
($name:ident) => {
|
|
paste::item! {
|
|
#[repr(C)]
|
|
pub struct [<wasm_ $name _vec_t>] {
|
|
pub size: usize,
|
|
pub data: *mut [<wasm_ $name _t>],
|
|
}
|
|
|
|
impl [<wasm_ $name _vec_t>] {
|
|
pub unsafe fn into_slice(&self) -> Option<&[[<wasm_ $name _t>]]>{
|
|
if self.data.is_null() {
|
|
return None;
|
|
}
|
|
|
|
Some(slice::from_raw_parts(self.data, self.size))
|
|
}
|
|
}
|
|
|
|
// TODO: investigate possible memory leak on `init` (owned pointer)
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *mut [<wasm_ $name _t>]) {
|
|
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length);
|
|
for i in 0..length {
|
|
bytes.push(ptr::read(init.add(i)));
|
|
}
|
|
let pointer = bytes.as_mut_ptr();
|
|
debug_assert!(bytes.len() == bytes.capacity());
|
|
(*out).data = pointer;
|
|
(*out).size = length;
|
|
mem::forget(bytes);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) {
|
|
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length);
|
|
let pointer = bytes.as_mut_ptr();
|
|
(*out).data = pointer;
|
|
(*out).size = length;
|
|
mem::forget(bytes);
|
|
}
|
|
}
|
|
wasm_declare_vec_inner!($name);
|
|
};
|
|
}
|
|
|
|
macro_rules! wasm_declare_boxed_vec {
|
|
($name:ident) => {
|
|
paste::item! {
|
|
#[repr(C)]
|
|
pub struct [<wasm_ $name _vec_t>] {
|
|
pub size: usize,
|
|
pub data: *mut *mut [<wasm_ $name _t>],
|
|
}
|
|
|
|
// TODO: do this properly
|
|
impl [<wasm_ $name _vec_t>] {
|
|
pub unsafe fn into_slice(&self) -> Option<&[*mut [<wasm_ $name _t>]]>{
|
|
if self.data.is_null() {
|
|
return None;
|
|
}
|
|
|
|
Some(slice::from_raw_parts(self.data, self.size))
|
|
}
|
|
}
|
|
|
|
// TODO: investigate possible memory leak on `init` (owned pointer)
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *const *mut [<wasm_ $name _t>]) {
|
|
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length);
|
|
for i in 0..length {
|
|
bytes.push(*init.add(i));
|
|
}
|
|
let pointer = bytes.as_mut_ptr();
|
|
debug_assert!(bytes.len() == bytes.capacity());
|
|
(*out).data = pointer;
|
|
(*out).size = length;
|
|
mem::forget(bytes);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) {
|
|
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length);
|
|
let pointer = bytes.as_mut_ptr();
|
|
(*out).data = pointer;
|
|
(*out).size = length;
|
|
mem::forget(bytes);
|
|
}
|
|
}
|
|
wasm_declare_vec_inner!($name);
|
|
};
|
|
}
|
|
|
|
macro_rules! wasm_declare_ref_base {
|
|
($name:ident) => {
|
|
wasm_declare_own!($name);
|
|
paste::item! {
|
|
#[no_mangle]
|
|
pub extern "C" fn [<wasm_ $name _copy>](_arg: *const [<wasm_ $name _t>]) -> *mut [<wasm_ $name _t>] {
|
|
todo!("in generated declare ref base");
|
|
//ptr::null_mut()
|
|
}
|
|
|
|
// TODO: finish this...
|
|
|
|
}
|
|
};
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub type wasm_byte_t = u8;
|
|
wasm_declare_vec!(byte);
|
|
|
|
// opaque type over `ExternRef`?
|
|
#[allow(non_camel_case_types)]
|
|
pub struct wasm_ref_t;
|
|
|
|
// opaque type which is a `RuntimeError`
|
|
#[repr(C)]
|
|
pub struct wasm_trap_t {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_trap_delete(trap: Option<NonNull<wasm_trap_t>>) {
|
|
if let Some(t_inner) = trap {
|
|
let _ = Box::from_raw(t_inner.cast::<RuntimeError>().as_ptr());
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_trap_message(
|
|
trap: *const wasm_trap_t,
|
|
out_ptr: *mut wasm_byte_vec_t,
|
|
) {
|
|
let re = &*(trap as *const RuntimeError);
|
|
// this code assumes no nul bytes appear in the message
|
|
let mut message = format!("{}\0", re);
|
|
message.shrink_to_fit();
|
|
|
|
// TODO use `String::into_raw_parts` when it gets stabilized
|
|
(*out_ptr).size = message.as_bytes().len();
|
|
(*out_ptr).data = message.as_mut_ptr();
|
|
mem::forget(message);
|
|
}
|
|
|
|
// in trap/RuntimeError we need to store
|
|
// 1. message
|
|
// 2. origin (frame); frame contains:
|
|
// 1. func index
|
|
// 2. func offset
|
|
// 3. module offset
|
|
// 4. which instance this was apart of
|
|
|
|
/*#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_trap_trace(trap: *const wasm_trap_t, out_ptr: *mut wasm_frame_vec_t) {
|
|
let re = &*(trap as *const RuntimeError);
|
|
todo!()
|
|
}*/
|
|
|
|
#[repr(C)]
|
|
pub struct wasm_extern_t {
|
|
// this is how we ensure the instance stays alive
|
|
instance: Option<Arc<Instance>>,
|
|
inner: Extern,
|
|
}
|
|
wasm_declare_boxed_vec!(extern);
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
#[repr(C)]
|
|
pub struct wasm_valtype_t {
|
|
valkind: wasm_valkind_enum,
|
|
}
|
|
|
|
impl Default for wasm_valtype_t {
|
|
fn default() -> Self {
|
|
Self {
|
|
valkind: wasm_valkind_enum::WASM_I32,
|
|
}
|
|
}
|
|
}
|
|
|
|
wasm_declare_boxed_vec!(valtype);
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option<Box<wasm_valtype_t>> {
|
|
let kind_enum = kind.try_into().ok()?;
|
|
let valtype = wasm_valtype_t { valkind: kind_enum };
|
|
Some(Box::new(valtype))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_valtype_delete(_valtype: Option<Box<wasm_valtype_t>>) {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_valtype_kind(valtype: *const wasm_valtype_t) -> wasm_valkind_t {
|
|
if valtype.is_null() {
|
|
// TODO: handle error
|
|
panic!("wasm_valtype_kind: argument is null pointer");
|
|
}
|
|
return (*valtype).valkind as wasm_valkind_t;
|
|
}
|
|
|
|
//wasm_declare_ref!(trap);
|
|
//wasm_declare_ref!(foreign);
|
|
|
|
#[derive(Clone, Debug)]
|
|
#[repr(transparent)]
|
|
#[allow(non_camel_case_types)]
|
|
pub struct wasm_globaltype_t {
|
|
extern_: wasm_externtype_t,
|
|
}
|
|
|
|
impl wasm_globaltype_t {
|
|
fn as_globaltype(&self) -> &GlobalType {
|
|
if let ExternType::Global(ref g) = self.extern_.inner {
|
|
g
|
|
} else {
|
|
unreachable!(
|
|
"Data corruption detected: `wasm_globaltype_t` does not contain a `GlobalType`"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
wasm_declare_vec!(globaltype);
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_globaltype_new(
|
|
// own
|
|
valtype: Option<Box<wasm_valtype_t>>,
|
|
mutability: wasm_mutability_t,
|
|
) -> Option<Box<wasm_globaltype_t>> {
|
|
wasm_globaltype_new_inner(valtype?, mutability)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: Option<Box<wasm_globaltype_t>>) {}
|
|
|
|
unsafe fn wasm_globaltype_new_inner(
|
|
// own
|
|
valtype: Box<wasm_valtype_t>,
|
|
mutability: wasm_mutability_t,
|
|
) -> Option<Box<wasm_globaltype_t>> {
|
|
let me: wasm_mutability_enum = mutability.try_into().ok()?;
|
|
let gd = Box::new(wasm_globaltype_t {
|
|
extern_: wasm_externtype_t {
|
|
inner: ExternType::Global(GlobalType::new((*valtype).into(), me.into())),
|
|
},
|
|
});
|
|
wasm_valtype_delete(Some(valtype));
|
|
|
|
Some(gd)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_globaltype_mutability(
|
|
globaltype: &wasm_globaltype_t,
|
|
) -> wasm_mutability_t {
|
|
let gt = globaltype.as_globaltype();
|
|
wasm_mutability_enum::from(gt.mutability).into()
|
|
}
|
|
|
|
// TODO: fix memory leak
|
|
// this function leaks memory because the returned limits pointer is not owned
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_globaltype_content(
|
|
globaltype: &wasm_globaltype_t,
|
|
) -> *const wasm_valtype_t {
|
|
let gt = globaltype.as_globaltype();
|
|
Box::into_raw(Box::new(gt.ty.into()))
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
#[repr(C)]
|
|
#[allow(non_camel_case_types)]
|
|
pub struct wasm_tabletype_t {
|
|
extern_: wasm_externtype_t,
|
|
}
|
|
|
|
wasm_declare_vec!(tabletype);
|
|
|
|
impl wasm_tabletype_t {
|
|
fn as_tabletype(&self) -> &TableType {
|
|
if let ExternType::Table(ref t) = self.extern_.inner {
|
|
t
|
|
} else {
|
|
unreachable!(
|
|
"Data corruption detected: `wasm_tabletype_t` does not contain a `TableType`"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_tabletype_new(
|
|
// own
|
|
valtype: Box<wasm_valtype_t>,
|
|
limits: &wasm_limits_t,
|
|
) -> Box<wasm_tabletype_t> {
|
|
// TODO: investigate if `0` is in fact a sentinel value here
|
|
let max_elements = if limits.max == 0 {
|
|
None
|
|
} else {
|
|
Some(limits.max as _)
|
|
};
|
|
let out = Box::new(wasm_tabletype_t {
|
|
extern_: wasm_externtype_t {
|
|
inner: ExternType::Table(TableType::new(
|
|
(*valtype).into(),
|
|
limits.min as _,
|
|
max_elements,
|
|
)),
|
|
},
|
|
});
|
|
wasm_valtype_delete(Some(valtype));
|
|
|
|
out
|
|
}
|
|
|
|
// TODO: fix memory leak
|
|
// this function leaks memory because the returned limits pointer is not owned
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_tabletype_limits(
|
|
tabletype: &wasm_tabletype_t,
|
|
) -> *const wasm_limits_t {
|
|
let tt = tabletype.as_tabletype();
|
|
Box::into_raw(Box::new(wasm_limits_t {
|
|
min: tt.minimum as _,
|
|
max: tt.maximum.unwrap_or(0),
|
|
}))
|
|
}
|
|
|
|
// TODO: fix memory leak
|
|
// this function leaks memory because the returned limits pointer is not owned
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_tabletype_element(
|
|
tabletype: &wasm_tabletype_t,
|
|
) -> *const wasm_valtype_t {
|
|
let tt = tabletype.as_tabletype();
|
|
|
|
Box::into_raw(Box::new(tt.ty.into()))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option<Box<wasm_tabletype_t>>) {}
|
|
|
|
// opaque type wrapping `MemoryType`
|
|
#[derive(Clone, Debug)]
|
|
#[repr(transparent)]
|
|
#[allow(non_camel_case_types)]
|
|
pub struct wasm_memorytype_t {
|
|
extern_: wasm_externtype_t,
|
|
}
|
|
|
|
impl wasm_memorytype_t {
|
|
pub(crate) fn as_memorytype(&self) -> &MemoryType {
|
|
if let ExternType::Memory(ref mt) = self.extern_.inner {
|
|
mt
|
|
} else {
|
|
unreachable!(
|
|
"Data corruption detected: `wasm_memorytype_t` does not contain a `MemoryType`"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
wasm_declare_vec!(memorytype);
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
#[repr(C)]
|
|
pub struct wasm_limits_t {
|
|
min: u32,
|
|
max: u32,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {
|
|
let min_pages = Pages(limits.min as _);
|
|
// TODO: investigate if `0` is in fact a sentinel value here
|
|
let max_pages = if limits.max == 0 {
|
|
None
|
|
} else {
|
|
Some(Pages(limits.max as _))
|
|
};
|
|
Box::new(wasm_memorytype_t {
|
|
extern_: wasm_externtype_t {
|
|
inner: ExternType::Memory(MemoryType::new(min_pages, max_pages, false)),
|
|
},
|
|
})
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memorytype_delete(_memorytype: Option<Box<wasm_memorytype_t>>) {}
|
|
|
|
// TODO: fix memory leak
|
|
// this function leaks memory because the returned limits pointer is not owned
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> *const wasm_limits_t {
|
|
let md = mt.as_memorytype();
|
|
Box::into_raw(Box::new(wasm_limits_t {
|
|
min: md.minimum.bytes().0 as _,
|
|
max: md.maximum.map(|max| max.bytes().0 as _).unwrap_or(0),
|
|
}))
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(transparent)]
|
|
pub struct wasm_functype_t {
|
|
extern_: wasm_externtype_t,
|
|
}
|
|
|
|
impl wasm_functype_t {
|
|
pub(crate) fn sig(&self) -> &FunctionType {
|
|
if let ExternType::Function(ref f) = self.extern_.inner {
|
|
f
|
|
} else {
|
|
unreachable!("data corruption: `wasm_functype_t` does not contain a function")
|
|
}
|
|
}
|
|
}
|
|
|
|
wasm_declare_vec!(functype);
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_new(
|
|
// own
|
|
params: Option<NonNull<wasm_valtype_vec_t>>,
|
|
// own
|
|
results: Option<NonNull<wasm_valtype_vec_t>>,
|
|
) -> Option<Box<wasm_functype_t>> {
|
|
wasm_functype_new_inner(params?, results?)
|
|
}
|
|
|
|
unsafe fn wasm_functype_new_inner(
|
|
// own
|
|
params: NonNull<wasm_valtype_vec_t>,
|
|
// own
|
|
results: NonNull<wasm_valtype_vec_t>,
|
|
) -> Option<Box<wasm_functype_t>> {
|
|
let params = params.as_ref();
|
|
let results = results.as_ref();
|
|
let params: Vec<ValType> = params
|
|
.into_slice()?
|
|
.iter()
|
|
.map(|&ptr| *ptr)
|
|
.map(Into::into)
|
|
.collect::<Vec<_>>();
|
|
let results: Vec<ValType> = results
|
|
.into_slice()?
|
|
.iter()
|
|
.map(|&ptr| *ptr)
|
|
.map(Into::into)
|
|
.collect::<Vec<_>>();
|
|
|
|
let extern_ = wasm_externtype_t {
|
|
inner: ExternType::Function(FunctionType::new(params, results)),
|
|
};
|
|
Some(Box::new(wasm_functype_t { extern_ }))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_delete(_ft: Option<Box<wasm_functype_t>>) {}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_copy(
|
|
arg: Option<NonNull<wasm_functype_t>>,
|
|
) -> Option<Box<wasm_functype_t>> {
|
|
let arg = arg?;
|
|
let funcsig = arg.as_ref();
|
|
Some(Box::new(funcsig.clone()))
|
|
}
|
|
|
|
// TODO: fix memory leak
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
|
|
let mut valtypes = ft
|
|
.sig()
|
|
.params()
|
|
.iter()
|
|
.cloned()
|
|
.map(Into::into)
|
|
.map(Box::new)
|
|
.map(Box::into_raw)
|
|
.collect::<Vec<*mut wasm_valtype_t>>();
|
|
let out = Box::into_raw(Box::new(wasm_valtype_vec_t {
|
|
size: valtypes.len(),
|
|
data: valtypes.as_mut_ptr(),
|
|
}));
|
|
mem::forget(valtypes);
|
|
out as *const _
|
|
}
|
|
|
|
// TODO: fix memory leak
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
|
|
let mut valtypes = ft
|
|
.sig()
|
|
.results()
|
|
.iter()
|
|
.cloned()
|
|
.map(Into::into)
|
|
.map(Box::new)
|
|
.map(Box::into_raw)
|
|
.collect::<Vec<*mut wasm_valtype_t>>();
|
|
let out = Box::into_raw(Box::new(wasm_valtype_vec_t {
|
|
size: valtypes.len(),
|
|
data: valtypes.as_mut_ptr(),
|
|
}));
|
|
mem::forget(valtypes);
|
|
out as *const _
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(C)]
|
|
pub struct wasm_frame_t {}
|
|
|
|
wasm_declare_vec!(frame);
|
|
|
|
#[derive(Clone, Debug)]
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(transparent)]
|
|
pub struct wasm_externtype_t {
|
|
inner: ExternType,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
|
Box::new(wasm_externtype_t {
|
|
inner: e.inner.ty(),
|
|
})
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_delete(_et: Option<Box<wasm_externtype_t>>) {}
|
|
|
|
impl From<ExternType> for wasm_externtype_t {
|
|
fn from(other: ExternType) -> Self {
|
|
Self { inner: other }
|
|
}
|
|
}
|
|
|
|
impl From<&ExternType> for wasm_externtype_t {
|
|
fn from(other: &ExternType) -> Self {
|
|
other.clone().into()
|
|
}
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
type wasm_externkind_t = u8;
|
|
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(u8)]
|
|
pub enum wasm_externkind_enum {
|
|
WASM_EXTERN_FUNC = 0,
|
|
WASM_EXTERN_GLOBAL = 1,
|
|
WASM_EXTERN_TABLE = 2,
|
|
WASM_EXTERN_MEMORY = 3,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
|
|
wasm_externkind_enum::from(e.inner.ty()) as wasm_externkind_t
|
|
}
|
|
|
|
impl From<ExternType> for wasm_externkind_enum {
|
|
fn from(other: ExternType) -> Self {
|
|
(&other).into()
|
|
}
|
|
}
|
|
impl From<&ExternType> for wasm_externkind_enum {
|
|
fn from(other: &ExternType) -> Self {
|
|
match other {
|
|
ExternType::Function(_) => Self::WASM_EXTERN_FUNC,
|
|
ExternType::Global(_) => Self::WASM_EXTERN_GLOBAL,
|
|
ExternType::Table(_) => Self::WASM_EXTERN_TABLE,
|
|
ExternType::Memory(_) => Self::WASM_EXTERN_MEMORY,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t {
|
|
wasm_externkind_enum::from(&et.inner) as wasm_externkind_t
|
|
}
|
|
|
|
#[derive(Debug, Clone, Error)]
|
|
#[error("failed to convert from `wasm_externtype_t`: {0}")]
|
|
pub struct ExternTypeConversionError(&'static str);
|
|
impl From<&'static str> for ExternTypeConversionError {
|
|
fn from(other: &'static str) -> Self {
|
|
Self(other)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_functype_t {
|
|
type Error = ExternTypeConversionError;
|
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
|
if let ExternType::Function(_) = other.inner {
|
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
|
} else {
|
|
Err(ExternTypeConversionError("Wrong type: expected function"))
|
|
}
|
|
}
|
|
}
|
|
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
|
|
type Error = ExternTypeConversionError;
|
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
|
if let ExternType::Global(_) = other.inner {
|
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
|
} else {
|
|
Err(ExternTypeConversionError("Wrong type: expected global"))
|
|
}
|
|
}
|
|
}
|
|
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t {
|
|
type Error = ExternTypeConversionError;
|
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
|
if let ExternType::Memory(_) = other.inner {
|
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
|
} else {
|
|
Err(ExternTypeConversionError("Wrong type: expected memory"))
|
|
}
|
|
}
|
|
}
|
|
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
|
|
type Error = ExternTypeConversionError;
|
|
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
|
if let ExternType::Table(_) = other.inner {
|
|
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
|
} else {
|
|
Err(ExternTypeConversionError("Wrong type: expected table"))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_functype_const(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_functype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_functype(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_functype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_as_externtype_const(
|
|
ft: &'static wasm_functype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
&ft.extern_
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_functype_as_externtype(
|
|
ft: &'static wasm_functype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
&ft.extern_
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_memorytype_const(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_memorytype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_memorytype(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_memorytype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memorytype_as_externtype_const(
|
|
mt: &'static wasm_memorytype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
&mt.extern_
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_memorytype_as_externtype(
|
|
mt: &'static wasm_memorytype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
&mt.extern_
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_globaltype_const(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_globaltype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_globaltype(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_globaltype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_globaltype_as_externtype_const(
|
|
gt: &'static wasm_globaltype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
>.extern_
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_globaltype_as_externtype(
|
|
gt: &'static wasm_globaltype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
>.extern_
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_tabletype_const(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_tabletype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_externtype_as_tabletype(
|
|
et: &'static wasm_externtype_t,
|
|
) -> Option<&'static wasm_tabletype_t> {
|
|
Some(c_try!(et.try_into()))
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_tabletype_as_externtype_const(
|
|
tt: &'static wasm_tabletype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
&tt.extern_
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn wasm_tabletype_as_externtype(
|
|
tt: &'static wasm_tabletype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
&tt.extern_
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
type wasm_name_t = wasm_byte_vec_t;
|
|
|
|
#[repr(C)]
|
|
#[allow(non_camel_case_types)]
|
|
pub struct wasm_exporttype_t {
|
|
name: NonNull<wasm_name_t>,
|
|
extern_type: NonNull<wasm_externtype_t>,
|
|
}
|
|
|
|
wasm_declare_boxed_vec!(exporttype);
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_exporttype_new(
|
|
name: NonNull<wasm_name_t>,
|
|
extern_type: NonNull<wasm_externtype_t>,
|
|
) -> Box<wasm_exporttype_t> {
|
|
Box::new(wasm_exporttype_t { name, extern_type })
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_exporttype_name(et: &'static wasm_exporttype_t) -> &'static wasm_name_t {
|
|
unsafe { et.name.as_ref() }
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_exporttype_type(
|
|
et: &'static wasm_exporttype_t,
|
|
) -> &'static wasm_externtype_t {
|
|
unsafe { et.extern_type.as_ref() }
|
|
}
|
|
|
|
impl From<ExportType> for wasm_exporttype_t {
|
|
fn from(other: ExportType) -> Self {
|
|
(&other).into()
|
|
}
|
|
}
|
|
|
|
impl From<&ExportType> for wasm_exporttype_t {
|
|
fn from(other: &ExportType) -> Self {
|
|
// TODO: double check that freeing String as `Vec<u8>` is valid
|
|
let name = {
|
|
let mut heap_str: Box<str> = other.name().to_string().into_boxed_str();
|
|
let char_ptr = heap_str.as_mut_ptr();
|
|
let str_len = heap_str.bytes().len();
|
|
let name_inner = wasm_name_t {
|
|
size: str_len,
|
|
data: char_ptr,
|
|
};
|
|
Box::leak(heap_str);
|
|
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) }
|
|
};
|
|
|
|
let extern_type = {
|
|
let extern_type: wasm_externtype_t = other.ty().into();
|
|
unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) }
|
|
};
|
|
|
|
wasm_exporttype_t { name, extern_type }
|
|
}
|
|
}
|