Macroization of the code

This commit is contained in:
Adrián Arroyo Calle
2023-02-25 22:27:28 +01:00
parent 9d52d2a653
commit 92b262d599
3 changed files with 136 additions and 101 deletions

View File

@@ -120,61 +120,32 @@ impl ForeignFunctionTable {
Ok(())
}
fn build_pointer_args(mut args: &mut Vec<Value>, type_args: &Vec<*mut ffi_type>, structs_table: &mut HashMap<String, StructImpl>) -> Result<PointerArgs, FFIError> {
fn build_pointer_args(args: &mut Vec<Value>, type_args: &Vec<*mut ffi_type>, structs_table: &mut HashMap<String, StructImpl>) -> Result<PointerArgs, FFIError> {
let mut pointers = Vec::with_capacity(args.len());
let mut memory = Vec::new();
for i in 0..args.len() {
let field_type = type_args[i];
unsafe {
macro_rules! push_int {
($type:ty) => {
{
let n: $type = <$type>::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
}
}
}
match (*field_type).type_ as u32 {
libffi::raw::FFI_TYPE_UINT8 => {
let n: u8 = u8::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_SINT8 => {
let n: i8 = i8::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_UINT16 => {
let n: u16 = u16::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_SINT16 => {
let n: i16 = i16::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_UINT32 => {
let n: u32 = u32::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_SINT32 => {
let n: i32 = i32::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_UINT64 => {
let n: u64 = u64::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
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);
},
libffi::raw::FFI_TYPE_SINT64 => {
let n: i64 = 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);
},
libffi::raw::FFI_TYPE_UINT8 => push_int!(u8),
libffi::raw::FFI_TYPE_SINT8 => push_int!(i8),
libffi::raw::FFI_TYPE_UINT16 => push_int!(u16),
libffi::raw::FFI_TYPE_SINT16 => push_int!(i16),
libffi::raw::FFI_TYPE_UINT32 => push_int!(u32),
libffi::raw::FFI_TYPE_SINT32 => push_int!(i32),
libffi::raw::FFI_TYPE_UINT64 => push_int!(u64),
libffi::raw::FFI_TYPE_SINT64 => push_int!(i64),
libffi::raw::FFI_TYPE_FLOAT => {
let n: f32 = args[i].as_float()? as f32;
let mut box_value = Box::new(n) as Box<dyn Any>;
@@ -193,34 +164,46 @@ impl ForeignFunctionTable {
},
libffi::raw::FFI_TYPE_STRUCT => {
match args[i] {
Value::Struct(ref name, ref struct_args) => {
Value::Struct(ref name, ref mut struct_args) => {
if let Some(ref mut struct_type) = structs_table.get_mut(name) {
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
let ptr = alloc(layout) as *mut c_void;
let mut field_ptr = ptr;
for i in 0..(struct_type.fields.len()-1) {
macro_rules! try_write_int {
($type:ty) => {
{
let n: $type = <$type>::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
std::ptr::write(field_ptr as *mut $type, n);
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
}
}
}
macro_rules! write {
($type:ty, $value:expr) => {
{
let data: $type = $value;
std::ptr::write(field_ptr as *mut $type, data);
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
}
}
}
let field = struct_type.fields[i];
match (*field).type_ as u32 {
libffi::raw::FFI_TYPE_UINT8 => {
let n: u8 = u8::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
std::ptr::write(field_ptr as *mut u8, n);
field_ptr = field_ptr.add(std::mem::size_of::<u8>());
},
libffi::raw::FFI_TYPE_UINT32 => {
let n: u32 = u32::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
std::ptr::write(field_ptr as *mut u32, n);
field_ptr = field_ptr.add(std::mem::size_of::<u32>());
},
libffi::raw::FFI_TYPE_SINT32 => {
let n: u32 = u32::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?;
std::ptr::write(field_ptr as *mut u32, n);
field_ptr = field_ptr.add(std::mem::size_of::<u32>());
},
libffi::raw::FFI_TYPE_FLOAT => {
let n: f32 = struct_args[i].as_float()? as f32;
std::ptr::write(field_ptr as *mut f32, n);
field_ptr = field_ptr.add(std::mem::size_of::<f32>());
},
libffi::raw::FFI_TYPE_UINT8 => try_write_int!(u8),
libffi::raw::FFI_TYPE_SINT8 => try_write_int!(i8),
libffi::raw::FFI_TYPE_UINT16 => try_write_int!(u16),
libffi::raw::FFI_TYPE_SINT16 => try_write_int!(i16),
libffi::raw::FFI_TYPE_UINT32 => try_write_int!(u32),
libffi::raw::FFI_TYPE_SINT32 => try_write_int!(i32),
libffi::raw::FFI_TYPE_UINT64 => try_write_int!(u64),
libffi::raw::FFI_TYPE_SINT64 => try_write_int!(i64),
libffi::raw::FFI_TYPE_POINTER => write!(*mut c_void, struct_args[i].as_ptr()?),
libffi::raw::FFI_TYPE_FLOAT => write!(f32, struct_args[i].as_float()? as f32),
libffi::raw::FFI_TYPE_DOUBLE => write!(f64, struct_args[i].as_float()?),
_ => {
unreachable!()
}
@@ -247,42 +230,66 @@ impl ForeignFunctionTable {
pub fn exec(&mut self, name: &str, mut args: Vec<Value>) -> 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).unwrap();
let mut pointer_args = Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
return unsafe {
macro_rules! call_and_return {
($type:ty) => {
{
let mut n: Box<u8> = 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() as *mut *mut c_void
);
Ok(Value::Int(i64::from(*n)))
}
}
}
match (*function_impl.cif.rtype).type_ as u32 {
libffi::raw::FFI_TYPE_VOID => {
let mut _n: Box<i32> = Box::new(0);
libffi::raw::FFI_TYPE_VOID => call_and_return!(i32),
libffi::raw::FFI_TYPE_UINT8 => call_and_return!(u8),
libffi::raw::FFI_TYPE_SINT8 => call_and_return!(i8),
libffi::raw::FFI_TYPE_UINT16 => call_and_return!(u16),
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,
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Int(0))
Ok(Value::Int(i64::try_from(*n).map_err(|_| FFIError::ValueDontFit)?))
},
libffi::raw::FFI_TYPE_SINT8 => {
let mut n: Box<i8> = Box::new(0);
libffi::raw::FFI_TYPE_SINT64 => call_and_return!(i64),
libffi::raw::FFI_TYPE_FLOAT => {
let mut n: Box<f32> = Box::new(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,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Int(i64::from(*n)))
},
libffi::raw::FFI_TYPE_SINT32 => {
let mut n: Box<i32> = Box::new(0);
Ok(Value::Float((*n).into()))
},
libffi::raw::FFI_TYPE_DOUBLE => {
let mut n: Box<f64> = Box::new(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,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Int(i64::from(*n)))
Ok(Value::Float(*n))
},
libffi::raw::FFI_TYPE_STRUCT => {
let mut returns = Vec::new();
let mut struct_type = self.structs.get_mut(&function_impl.return_struct_name.clone().ok_or(FFIError::StructNotFound)?).ok_or(FFIError::StructNotFound)?;
let struct_type = self.structs.get_mut(&function_impl.return_struct_name.clone().ok_or(FFIError::StructNotFound)?).ok_or(FFIError::StructNotFound)?;
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
let ptr = alloc(layout) as *mut c_void;
libffi::raw::ffi_call(
@@ -292,25 +299,33 @@ impl ForeignFunctionTable {
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
let mut field_ptr = ptr;
let mut field_ptr = ptr;
macro_rules! read_and_push_int {
($type:ty) => {
{
let n = std::ptr::read(field_ptr as *mut $type);
returns.push(Value::Int(i64::from(n)));
field_ptr = field_ptr.add(std::mem::size_of::<$type>());
}
}
}
for i in 0..(struct_type.fields.len()-1) {
let field = struct_type.fields[i];
match (*field).type_ as u32 {
libffi::raw::FFI_TYPE_UINT8 => {
let n = std::ptr::read(field_ptr as *mut u8);
returns.push(Value::Int(i64::from(n)));
field_ptr = field_ptr.add(std::mem::size_of::<u8>());
},
libffi::raw::FFI_TYPE_SINT32 => {
let n = std::ptr::read(field_ptr as *mut i32);
returns.push(Value::Int(i64::from(n)));
field_ptr = field_ptr.add(std::mem::size_of::<i32>());
},
libffi::raw::FFI_TYPE_UINT32 => {
let n = std::ptr::read(field_ptr as *mut u32);
returns.push(Value::Int(i64::from(n)));
field_ptr = field_ptr.add(std::mem::size_of::<u32>());
libffi::raw::FFI_TYPE_UINT8 => read_and_push_int!(u8),
libffi::raw::FFI_TYPE_SINT8 => read_and_push_int!(i8),
libffi::raw::FFI_TYPE_UINT16 => read_and_push_int!(u16),
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 => {
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_SINT64 => read_and_push_int!(i64),
_ => {
unreachable!()
}

View File

@@ -1,6 +1,7 @@
use crate::atom_table::*;
use crate::parser::ast::*;
use crate::ffi::FFIError;
use crate::forms::*;
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
@@ -515,6 +516,24 @@ impl MachineState {
}
}
pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
let error_atom = match err {
FFIError::ValueCast => atom!("value_cast"),
FFIError::ValueDontFit => atom!("value_dont_fit"),
FFIError::InvalidFFIType => atom!("invalid_ffi_type"),
FFIError::InvalidStructName => atom!("invalid_struct_name"),
FFIError::FunctionNotFound => atom!("function_not_found"),
FFIError::StructNotFound => atom!("struct_not_found"),
};
let stub = functor!(atom!("ffi_error"),[atom(error_atom)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
let h = self.heap.len();
let location = err.location;

View File

@@ -4288,9 +4288,10 @@ impl Machine {
return Ok(());
},
Err(e) => {
// throw error
self.machine_st.fail = true;
return Ok(());
let stub = functor_stub(atom!("current_input"), 1);
let err = self.machine_st.ffi_error(e);
return Err(self.machine_st.error_form(err, stub));
}
}
}