Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ parking_lot = "0.12.4"
crossterm = { version = "0.28.1", optional = true }
ctrlc = { version = "3.4.4", optional = true }
hostname = { version = "0.4.0", optional = true }
libffi = { version = "4.0.0", optional = true }
libffi = { version = "5.1.0", optional = true }
native-tls = { version = "0.2.12", optional = true }
# the version requirement of reqwest is kept low for compatibility with old deno versions
# that pin reqwest to 0.11.20
Expand Down
103 changes: 45 additions & 58 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::machine::machine_errors::DomainErrorType;
use crate::parser::ast::{Fixnum, MightNotFitInFixnum};

use dashu::Integer;
use libffi::middle::{Arg, Cif, CodePtr, Type};
use libffi::middle::{Arg, Cif, CodePtr, Ret, Type};
use libloading::{Library, Symbol};
use ordered_float::OrderedFloat;
use std::alloc::{self, Layout};
Expand All @@ -36,7 +36,6 @@ use std::ffi::{c_char, c_void, CStr, CString};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::ptr::NonNull;

pub struct FunctionDefinition {
Expand All @@ -55,7 +54,7 @@ pub struct FunctionImpl {

impl FunctionImpl {
unsafe fn call_void(&self, args: &[Arg], _: &mut Arena) -> Result<Value, FfiError> {
self.cif.call::<()>(self.code_ptr, args);
self.cif.call_return_into(self.code_ptr, args, Ret::void());
Ok(Value::Number(Number::Fixnum(Fixnum::build_with(0))))
}

Expand Down Expand Up @@ -114,12 +113,8 @@ impl FunctionImpl {
let alloc = FfiStruct::new(layout, FfiAllocator::Rust)?;

unsafe {
libffi::raw::ffi_call(
self.cif.as_raw_ptr(),
Some(*self.code_ptr.as_safe_fun()),
alloc.ptr.as_ptr(),
args.as_ptr() as *mut *mut c_void,
)
self.cif
.call_return_into(self.code_ptr, args, alloc.as_ret())
};

let struct_val =
Expand Down Expand Up @@ -336,7 +331,9 @@ impl StructImpl {
substruct_type.read(field_ptr, *substruct, struct_table, arena)?;
Ok(struct_val)
}
FfiType::Void => return Err(FfiError::VoidArgumentType),
FfiType::Void => {
return Err(FfiError::UnsupportedArgumentType(Some(atom!("void"))))
}
};
returns.push(val?);
}
Expand All @@ -345,48 +342,6 @@ impl StructImpl {
}
}

struct PointerArgs<'a, 'val> {
memory: Vec<Arg>,
phantom: PhantomData<&'a mut ArgValue<'val>>,
}

impl<'args, 'val> PointerArgs<'args, 'val> {
fn new(args: &'args [ArgValue<'val>]) -> Self {
let args = args
.iter()
.map(|arg| match arg {
ArgValue::U8(a) => libffi::middle::arg(a),
ArgValue::I8(a) => libffi::middle::arg(a),
ArgValue::U16(a) => libffi::middle::arg(a),
ArgValue::I16(a) => libffi::middle::arg(a),
ArgValue::U32(a) => libffi::middle::arg(a),
ArgValue::I32(a) => libffi::middle::arg(a),
ArgValue::U64(a) => libffi::middle::arg(a),
ArgValue::I64(a) => libffi::middle::arg(a),
ArgValue::F32(a) => libffi::middle::arg(a),
ArgValue::F64(a) => libffi::middle::arg(a),
ArgValue::Ptr(ptr, _) => Arg::new(ptr),
ArgValue::Struct(s) => unsafe {
std::mem::transmute::<*mut c_void, Arg>(s.ptr.as_ptr())
},
})
.collect();

PointerArgs {
memory: args,
phantom: PhantomData,
}
}
}

impl Deref for PointerArgs<'_, '_> {
type Target = [Arg];

fn deref(&self) -> &Self::Target {
&self.memory
}
}

#[derive(Debug, Clone, Copy)]
enum FfiType {
Void,
Expand Down Expand Up @@ -543,7 +498,7 @@ impl<'val> ArgValue<'val> {
args,
)?))
}
FfiType::Void => Err(FfiError::VoidArgumentType),
FfiType::Void => Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))),
}
}

Expand All @@ -568,6 +523,28 @@ impl<'val> ArgValue<'val> {
.map(|(arg, arg_type)| ArgValue::new(arg, arg_type, structs_table))
.collect::<Result<Vec<_>, _>>()
}

fn as_arg<'res, 'this: 'res>(&'this self) -> Arg<'res>
where
'val: 'res,
{
match self {
ArgValue::U8(a) => libffi::middle::arg(a),
ArgValue::I8(a) => libffi::middle::arg(a),
ArgValue::U16(a) => libffi::middle::arg(a),
ArgValue::I16(a) => libffi::middle::arg(a),
ArgValue::U32(a) => libffi::middle::arg(a),
ArgValue::I32(a) => libffi::middle::arg(a),
ArgValue::U64(a) => libffi::middle::arg(a),
ArgValue::I64(a) => libffi::middle::arg(a),
ArgValue::F32(a) => libffi::middle::arg(a),
ArgValue::F64(a) => libffi::middle::arg(a),
ArgValue::Ptr(ptr, _) => Arg::new(ptr),
ArgValue::Struct(s) => unsafe {
std::mem::transmute::<*mut c_void, Arg>(s.ptr.as_ptr())
},
}
}
}

struct FfiStruct {
Expand Down Expand Up @@ -628,6 +605,10 @@ impl FfiStruct {
allocator,
})
}

fn as_ret(&self) -> libffi::middle::Ret<'_> {
unsafe { std::mem::transmute::<*mut c_void, Ret>(self.ptr.as_ptr()) }
}
}

impl Drop for FfiStruct {
Expand Down Expand Up @@ -727,7 +708,7 @@ impl ForeignFunctionTable {
&self.structs,
)?;

let args = PointerArgs::new(&args);
let args: Vec<_> = args.iter().map(|v| v.as_arg()).collect();

fn_impl.call(&args, arena, &self.structs)
}
Expand Down Expand Up @@ -755,7 +736,7 @@ impl ForeignFunctionTable {
}

match FfiType::from_atom(&kind) {
FfiType::Void => Err(FfiError::VoidArgumentType),
FfiType::Void => Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))),
FfiType::Bool => {
let val = args.as_int::<i8>()?;
let init = match val {
Expand Down Expand Up @@ -819,7 +800,7 @@ impl ForeignFunctionTable {
};

match FfiType::from_atom(&kind) {
FfiType::Void => Err(FfiError::VoidArgumentType),
FfiType::Void => Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))),
FfiType::U8 => Ok(unsafe { read_int::<u8>(ptr, arena) }),
FfiType::Bool | FfiType::I8 => Ok(unsafe { read_int::<i8>(ptr, arena) }),
FfiType::U16 => Ok(unsafe { read_int::<u16>(ptr, arena) }),
Expand Down Expand Up @@ -869,7 +850,7 @@ impl ForeignFunctionTable {
};

match FfiType::from_atom(&kind) {
FfiType::Void => return Err(FfiError::VoidArgumentType),
FfiType::Void => return Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))),
FfiType::Bool => deallocate_primitive::<bool>(allocator, ptr),
FfiType::U8 => deallocate_primitive::<u8>(allocator, ptr),
FfiType::I8 => deallocate_primitive::<i8>(allocator, ptr),
Expand Down Expand Up @@ -966,10 +947,11 @@ impl Value {
}

#[derive(Debug)]
#[non_exhaustive]
pub enum FfiError {
ValueCast(Atom, Atom),
ValueOutOfRange(DomainErrorType, Value),
VoidArgumentType,
UnsupportedArgumentType(Option<Atom>),
FunctionNotFound(Atom, usize),
StructNotFound(Atom),
ArgCountMismatch {
Expand All @@ -987,6 +969,9 @@ pub enum FfiError {
UnsupportedAbi,
CStrFieldType,
NullPtr,
#[doc(hidden)]
#[non_exhaustive]
Other,
}

#[derive(Debug)]
Expand All @@ -1008,6 +993,8 @@ impl From<libffi::low::Error> for FfiError {
match value {
libffi::low::Error::Typedef => FfiError::UnsupportedTypedef,
libffi::low::Error::Abi => FfiError::UnsupportedAbi,
libffi::low::Error::ArgType => FfiError::UnsupportedArgumentType(None),
_ => FfiError::Other,
}
}
}
8 changes: 6 additions & 2 deletions src/machine/machine_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,10 +737,13 @@ impl MachineState {
FfiError::LayoutError => self.representation_error(RepFlag::FfiLayout),
FfiError::UnsupportedTypedef => self.representation_error(RepFlag::FfiLayout),
FfiError::UnsupportedAbi => self.representation_error(RepFlag::FfiAbi),
FfiError::VoidArgumentType => self.domain_error(
FfiError::UnsupportedArgumentType(None) => self.domain_error(
DomainErrorType::FfiArgumentType,
atom_as_cell!(atom!("void")),
atom_as_cell!(atom!("unknown")),
),
FfiError::UnsupportedArgumentType(Some(kind)) => {
self.domain_error(DomainErrorType::FfiArgumentType, atom_as_cell!(kind))
}
FfiError::CStrFieldType => self.domain_error(
DomainErrorType::NonCStrFfiArgumentType,
atom_as_cell!(atom!("cstr")),
Expand All @@ -749,6 +752,7 @@ impl MachineState {
DomainErrorType::NonNullPtr,
fixnum_as_cell!(Fixnum::build_with(0)),
),
FfiError::Other => self.unreachable_error(),
}
}

Expand Down
Loading