diff --git a/core/wasm/accessor/number.rs b/core/wasm/accessor/number.rs index 8e4530c..76d3055 100644 --- a/core/wasm/accessor/number.rs +++ b/core/wasm/accessor/number.rs @@ -1,8 +1,9 @@ mod index; mod types; +use core::ffi::c_void; use index::current as index; -use types::{number::Type, JSNumber, Null, Number}; +use types::{ffi::CTuple, number::Type, JSNumber, Null, Number}; type Setter = unsafe fn(Number, JSNumber); type Getter = unsafe fn(Number) -> JSNumber; @@ -27,6 +28,13 @@ fn accessor(ty: Type) -> (Getter, Setter) { } } +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] +#[export_name = "cABIaccessor"] +fn c_accessor(ty: Type) -> CTuple<*const c_void, *const c_void> { + let (getter, setter) = accessor(ty); + CTuple::from((getter as *const c_void, setter as *const c_void)) +} + #[no_mangle] fn set(set: fn(Number, JSNumber), this: Number, val: JSNumber) { set(this, val) diff --git a/core/wasm/instance/number.rs b/core/wasm/instance/number.rs index 0891b0e..f8da05d 100644 --- a/core/wasm/instance/number.rs +++ b/core/wasm/instance/number.rs @@ -2,7 +2,7 @@ mod offset; mod types; use core::arch::wasm32::{memory_grow, memory_size}; -use types::{number::Type, Null, Number}; +use types::{ffi::CTuple, number::Type, Null, Number}; static PAGE: usize = u16::MAX as usize + 1; // 1 page = 64KiB = 65536 @@ -37,3 +37,9 @@ unsafe fn array_of(ty: Type, len: u16, nullable: bool) -> (Number, Null) { (Number { addr }, Null { addr: null_addr }) } + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] +#[export_name = "cABIallocate"] +unsafe fn c_array_of(ty: Type, len: u16, nullable: bool) -> CTuple { + CTuple::from(array_of(ty, len, nullable)) +} diff --git a/core/wasm/types/mod.rs b/core/wasm/types/mod.rs index c47b30b..765af7a 100644 --- a/core/wasm/types/mod.rs +++ b/core/wasm/types/mod.rs @@ -5,3 +5,86 @@ pub use number::{JSNumber, Number}; pub struct Null { pub addr: usize, } + +macro_rules! convert_between { + ($into:ty |$($G:ident)?| $from:ty) => { + impl$(<$G>)? From<$from> for $into { + fn from(ptr: $from) -> Self { + let addr = ptr as usize; + Self { addr } + } + } + impl$(<$G>)? From<$into> for $from { + fn from(value: $into) -> Self { + value.addr as Self + } + } + }; +} + +pub(crate) use convert_between; +convert_between!(Null |T| *const T); +convert_between!(Number |T| *const T); + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] +pub mod ffi { + use core::ffi::c_void; + use core::marker::PhantomData; + + #[repr(transparent)] + pub struct CTuple { + lhs: PhantomData, + rhs: PhantomData, + + #[cfg(target_pointer_width = "32")] + pub addr: u64, + + #[cfg(target_pointer_width = "16")] + pub addr: u32, + } + + impl From<(L, R)> for CTuple + where + L: Into<*const c_void>, + R: Into<*const c_void>, + { + fn from(tuple: (L, R)) -> Self { + let (lhs, rhs) = tuple; + let lead = (lhs.into() as u64) << usize::BITS; + let trail = rhs.into() as u64; + Self::from(lead & trail) + } + } + + impl From> for (L, R) + where + L: From<*const c_void>, + R: From<*const c_void>, + { + fn from(ctuple: CTuple) -> Self { + let lead = (ctuple.addr >> usize::BITS) as *const c_void; + let trail = ctuple.addr as *const c_void; + (L::from(lead), R::from(trail)) + } + } + + macro_rules! impl_From { + ($ty:ident, $Ty:ident<$($G:ident),+>) => { + impl<$($G),+> From<$ty> for $Ty<$($G),+> { + fn from(addr: $ty) -> Self { + Self { + addr, + lhs: PhantomData, + rhs: PhantomData, + } + } + } + } + } + + #[cfg(target_pointer_width = "32")] + impl_From!(u64, CTuple); + + #[cfg(target_pointer_width = "16")] + impl_From!(u32, CTuple); +}