#![cfg(not(target_arch = "wasm32"))]
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use super::native_tier::{NativeFn, NativeOutcome, NativeRet, SlotKind};
pub struct AotNativeFn {
addr: usize,
arity: usize,
_lib: Arc<libloading::Library>,
calls: Arc<AtomicU64>,
}
unsafe impl Send for AotNativeFn {}
unsafe impl Sync for AotNativeFn {}
impl AotNativeFn {
pub fn call_count(&self) -> u64 {
self.calls.load(Ordering::Relaxed)
}
}
impl NativeFn for AotNativeFn {
fn call(&self, args: &[i64], _pins: &[i64], _depth: usize) -> NativeOutcome {
self.calls.fetch_add(1, Ordering::Relaxed);
let a = self.addr;
let r = unsafe {
match self.arity {
0 => std::mem::transmute::<usize, extern "C" fn() -> i64>(a)(),
1 => std::mem::transmute::<usize, extern "C" fn(i64) -> i64>(a)(args[0]),
2 => std::mem::transmute::<usize, extern "C" fn(i64, i64) -> i64>(a)(args[0], args[1]),
3 => std::mem::transmute::<usize, extern "C" fn(i64, i64, i64) -> i64>(a)(
args[0], args[1], args[2],
),
4 => std::mem::transmute::<usize, extern "C" fn(i64, i64, i64, i64) -> i64>(a)(
args[0], args[1], args[2], args[3],
),
_ => return NativeOutcome::Deopt,
}
};
NativeOutcome::Return(r)
}
fn ret(&self) -> NativeRet {
NativeRet::Scalar(SlotKind::Int)
}
fn entry_ptr(&self) -> i64 {
0
}
fn published_regc(&self) -> i64 {
0
}
}
pub fn load_aot_native(
path: &std::path::Path,
symbol: &str,
arity: usize,
) -> Option<(Box<dyn NativeFn>, Arc<AtomicU64>)> {
let lib = unsafe { libloading::Library::new(path).ok()? };
let addr = unsafe {
let sym: libloading::Symbol<'_, extern "C" fn() -> i64> = lib.get(symbol.as_bytes()).ok()?;
(*sym) as usize
};
let calls = Arc::new(AtomicU64::new(0));
let nf = AotNativeFn {
addr,
arity,
_lib: Arc::new(lib),
calls: calls.clone(),
};
Some((Box::new(nf), calls))
}