and finally we add the pointer the size of what we've written.
*/
+use crate::arena::Arena;
use crate::atom_table::Atom;
+use crate::forms::Number;
+use crate::parser::ast::Fixnum;
+use dashu::Integer;
+use ordered_float::OrderedFloat;
use std::alloc::{self, Layout};
use std::any::Any;
use std::collections::HashMap;
-use std::convert::TryFrom;
use std::error::Error;
use std::ffi::{c_void, CString};
use std::ptr::addr_of_mut;
unsafe {
macro_rules! push_int {
($type:ty) => {{
- let n: $type = <$type>::try_from(args[i].as_int()?)
- .map_err(|_| FFIError::ValueDontFit)?;
+ let n: $type = args[i].as_int()?;
let mut box_value = Box::new(n) as Box<dyn Any>;
pointers.push(&mut *box_value as *mut _ as *mut c_void);
_memory.push(box_value);
($type:ty) => {{
field_ptr = field_ptr
.add(field_ptr.align_offset(std::mem::align_of::<$type>()));
- let n: $type = <$type>::try_from(struct_args[i].as_int()?)
- .map_err(|_| FFIError::ValueDontFit)?;
+ let n: $type = struct_args[i].as_int()?;
std::ptr::write(field_ptr as *mut $type, n);
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
}};
}
}
- pub fn exec(&mut self, name: &str, mut args: Vec<Value>) -> Result<Value, FFIError> {
+ pub fn exec(
+ &mut self,
+ name: &str,
+ mut args: Vec<Value>,
+ arena: &mut Arena,
+ ) -> Result<Value, FFIError> {
let function_impl = self.table.get_mut(name).ok_or(FFIError::FunctionNotFound)?;
let mut pointer_args =
Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
unsafe {
macro_rules! call_and_return {
($type:ty) => {{
- let mut n: Box<$type> = Box::new(0);
+ let mut n: $type = 0;
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
- &mut *n as *mut _ as *mut c_void,
+ &mut n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void,
);
- Ok(Value::Int(i64::from(*n)))
+ Ok(Value::Number(fixnum!(Number, n, arena)))
}};
}
libffi::raw::FFI_TYPE_SINT16 => call_and_return!(i16),
libffi::raw::FFI_TYPE_UINT32 => call_and_return!(u32),
libffi::raw::FFI_TYPE_SINT32 => call_and_return!(i32),
- libffi::raw::FFI_TYPE_UINT64 => {
- let mut n: Box<u64> = Box::new(0);
- libffi::raw::ffi_call(
- &mut function_impl.cif,
- Some(*function_impl.code_ptr.as_safe_fun()),
- &mut *n as *mut _ as *mut c_void,
- pointer_args.pointers.as_mut_ptr(),
- );
- Ok(Value::Int(
- i64::try_from(*n).map_err(|_| FFIError::ValueDontFit)?,
- ))
- }
+ libffi::raw::FFI_TYPE_UINT64 => call_and_return!(u64),
libffi::raw::FFI_TYPE_SINT64 => call_and_return!(i64),
libffi::raw::FFI_TYPE_POINTER => {
- let mut n: Box<*mut c_void> = Box::new(std::ptr::null_mut());
+ let mut n: *mut c_void = std::ptr::null_mut();
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
- &mut *n as *mut _ as *mut c_void,
+ &mut n as *mut *mut c_void as *mut c_void,
pointer_args.pointers.as_mut_ptr(),
);
- Ok(Value::Int(
- i64::try_from(*n as isize).map_err(|_| FFIError::ValueDontFit)?,
- ))
+ Ok(Value::Number(fixnum!(Number, n as isize, arena)))
}
libffi::raw::FFI_TYPE_FLOAT => {
- let mut n: Box<f32> = Box::new(0.0);
+ let mut n: f32 = 0.0;
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
- &mut *n as *mut _ as *mut c_void,
+ &mut n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr(),
);
- Ok(Value::Float((*n).into()))
+ Ok(Value::Number(Number::Float(OrderedFloat(n.into()))))
}
libffi::raw::FFI_TYPE_DOUBLE => {
- let mut n: Box<f64> = Box::new(0.0);
+ let mut n: f64 = 0.0;
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
- &mut *n as *mut _ as *mut c_void,
+ &mut n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr(),
);
- Ok(Value::Float(*n))
+ Ok(Value::Number(Number::Float(OrderedFloat(n))))
}
libffi::raw::FFI_TYPE_STRUCT => {
let name = &function_impl
&mut *ptr as *mut _,
pointer_args.pointers.as_mut_ptr(),
);
- let struct_val = self.read_struct(ptr, name, struct_type);
+ let struct_val = self.read_struct(ptr, name, struct_type, arena);
#[allow(clippy::from_raw_with_void_ptr)]
drop(Box::from_raw(ptr));
struct_val
ptr: *mut c_void,
name: &str,
struct_type: &StructImpl,
+ arena: &mut Arena,
) -> Result<Value, FFIError> {
unsafe {
let mut returns = Vec::new();
field_ptr =
field_ptr.add(field_ptr.align_offset(std::mem::align_of::<$type>()));
let n = std::ptr::read(field_ptr as *mut $type);
- returns.push(Value::Int(i64::from(n)));
+ returns.push(Value::Number(fixnum!(Number, n, arena)));
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
}};
}
libffi::raw::FFI_TYPE_SINT16 => read_and_push_int!(i16),
libffi::raw::FFI_TYPE_UINT32 => read_and_push_int!(u32),
libffi::raw::FFI_TYPE_SINT32 => read_and_push_int!(i32),
- libffi::raw::FFI_TYPE_UINT64 => {
- field_ptr =
- field_ptr.add(field_ptr.align_offset(std::mem::align_of::<u64>()));
- let n = std::ptr::read(field_ptr as *mut u64);
- returns.push(Value::Int(
- i64::try_from(n).map_err(|_| FFIError::ValueDontFit)?,
- ));
- field_ptr = field_ptr.add(std::mem::size_of::<u64>());
- }
+ libffi::raw::FFI_TYPE_UINT64 => read_and_push_int!(u64),
libffi::raw::FFI_TYPE_SINT64 => read_and_push_int!(i64),
libffi::raw::FFI_TYPE_POINTER => read_and_push_int!(i64),
libffi::raw::FFI_TYPE_FLOAT => {
field_ptr =
field_ptr.add(field_ptr.align_offset(std::mem::align_of::<f32>()));
let n: f32 = std::ptr::read(field_ptr as *mut f32);
- returns.push(Value::Float(n.into()));
+ returns.push(Value::Number(Number::Float(OrderedFloat(n.into()))));
field_ptr = field_ptr.add(std::mem::size_of::<f32>());
}
libffi::raw::FFI_TYPE_DOUBLE => {
field_ptr =
field_ptr.add(field_ptr.align_offset(std::mem::align_of::<f64>()));
let n: f64 = std::ptr::read(field_ptr as *mut f64);
- returns.push(Value::Float(n));
+ returns.push(Value::Number(Number::Float(OrderedFloat(n))));
field_ptr = field_ptr.add(std::mem::size_of::<f64>());
}
libffi::raw::FFI_TYPE_STRUCT => {
.ok_or(FFIError::StructNotFound)?;
field_ptr = field_ptr
.add(field_ptr.align_offset(struct_type.ffi_type.alignment as usize));
- let struct_val = self.read_struct(field_ptr, &substruct, struct_type);
+ let struct_val =
+ self.read_struct(field_ptr, &substruct, struct_type, arena);
returns.push(struct_val?);
field_ptr = field_ptr.add(struct_type.ffi_type.size);
}
#[derive(Clone, Debug)]
pub enum Value {
- Int(i64),
- Float(f64),
+ Number(Number),
CString(CString),
Struct(String, Vec<Value>),
}
impl Value {
- fn as_int(&self) -> Result<i64, FFIError> {
+ fn as_int<I>(&self) -> Result<I, FFIError>
+ where
+ Integer: TryInto<I>,
+ i64: TryInto<I>,
+ {
match self {
- Value::Int(n) => Ok(*n),
+ Value::Number(Number::Integer(ibig_ptr)) => {
+ let ibig: &Integer = ibig_ptr;
+ ibig.clone().try_into().map_err(|_| FFIError::ValueDontFit)
+ }
+ Value::Number(Number::Fixnum(fixnum)) => fixnum
+ .get_num()
+ .try_into()
+ .map_err(|_| FFIError::ValueDontFit),
_ => Err(FFIError::ValueCast),
}
}
fn as_float(&self) -> Result<f64, FFIError> {
match self {
- Value::Float(n) => Ok(*n),
- Value::Int(n) => Ok(*n as f64),
+ &Value::Number(Number::Float(OrderedFloat(f))) => Ok(f),
_ => Err(FFIError::ValueCast),
}
}
fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> {
match self {
Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void),
- Value::Int(n) => Ok(std::ptr::with_exposed_provenance_mut(*n as usize)),
+ Value::Number(Number::Fixnum(fixnum)) => Ok(std::ptr::with_exposed_provenance_mut(
+ fixnum.get_num() as usize,
+ )),
_ => Err(FFIError::ValueCast),
}
}
#[cfg(feature = "ffi")]
#[inline(always)]
pub(crate) fn foreign_call(&mut self) -> CallResult {
- use dashu::integer::IBig;
-
let function_name = self.deref_register(1);
let args_reg = self.deref_register(2);
let return_value = self.deref_register(3);
let stub_gen = || functor_stub(atom!("foreign_call"), 3);
fn map_arg(machine_st: &mut MachineState, source: HeapCellValue) -> crate::ffi::Value {
match Number::try_from((source, &machine_st.arena.f64_tbl)) {
- Ok(Number::Fixnum(n)) => Value::Int(n.get_num()),
- Ok(Number::Float(n)) => Value::Float(n.into_inner()),
+ Ok(number) => Value::Number(number),
_ => {
let stub_gen = || functor_stub(atom!("foreign_call"), 3);
if let Some(string) = machine_st.value_to_str_like(source) {
.into_iter()
.map(|x| map_arg(&mut self.machine_st, x))
.collect();
- match self
- .foreign_function_table
- .exec(&function_name.as_str(), args)
- {
+ match self.foreign_function_table.exec(
+ &function_name.as_str(),
+ args,
+ &mut self.machine_st.arena,
+ ) {
Ok(result) => {
match result {
- Value::Int(n) => {
- if let Ok(fixnum) = Fixnum::build_with_checked(n) {
+ Value::Number(n) => match n {
+ Number::Float(OrderedFloat(n)) => {
+ let n = float_alloc!(n, self.machine_st.arena);
+ self.machine_st.unify_f64(n, return_value)
+ }
+ Number::Integer(typed_arena_ptr) => {
+ self.machine_st.unify_big_int(typed_arena_ptr, return_value)
+ }
+ Number::Rational(typed_arena_ptr) => {
+ self.machine_st
+ .unify_rational(typed_arena_ptr, return_value);
+ }
+ Number::Fixnum(fixnum) => {
self.machine_st.unify_fixnum(fixnum, return_value)
- } else {
- let bigint = IBig::from(n);
- let bigint = arena_alloc!(
- bigint.clone(),
- &mut self.machine_st.arena
- );
- self.machine_st.unify_big_int(bigint, return_value)
}
- }
- Value::Float(n) => {
- let n = float_alloc!(n, self.machine_st.arena);
- self.machine_st.unify_f64(n, return_value)
- }
+ },
Value::Struct(name, args) => {
let struct_value = resource_error_call_result!(
self.machine_st,
fn build_struct(&mut self, name: &str, mut args: Vec<Value>) -> Result<HeapCellValue, usize> {
args.insert(0, Value::CString(CString::new(name).unwrap()));
- let mut expanded_args = Vec::with_capacity(args.len());
-
- for val in args {
- expanded_args.push(match val {
- Value::Int(n) => {
- if let Ok(fixnum) = Fixnum::build_with_checked(n) {
- fixnum_as_cell!(fixnum)
- } else {
- integer_as_cell!(Number::Integer(arena_alloc!(
- Integer::from(n),
- &mut self.machine_st.arena
- )))
- }
- }
- Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)),
- Value::CString(cstr) => atom_as_cell!(AtomTable::build_with(
- &self.machine_st.atom_tbl,
- &cstr.into_string().unwrap()
- )),
- Value::Struct(name, struct_args) => self.build_struct(&name, struct_args)?,
- });
- }
+ let cells: Vec<_> = args
+ .into_iter()
+ .map(|val| {
+ Ok(match val {
+ Value::Number(n) => match n {
+ Number::Float(OrderedFloat(f)) => {
+ HeapCellValue::from(float_alloc!(f, self.machine_st.arena))
+ }
+ _ => integer_as_cell!(n),
+ },
+ Value::CString(cstr) => atom_as_cell!(AtomTable::build_with(
+ &self.machine_st.atom_tbl,
+ &cstr.into_string().unwrap()
+ )),
+ Value::Struct(name, struct_args) => self.build_struct(&name, struct_args)?,
+ })
+ })
+ .collect::<Result<_, usize>>()?;
- sized_iter_to_heap_list(
- &mut self.machine_st.heap,
- expanded_args.len(),
- expanded_args.into_iter(),
- )
+ sized_iter_to_heap_list(&mut self.machine_st.heap, cells.len(), cells.into_iter())
}
#[cfg(feature = "ffi")]