Skip to content

Commit

Permalink
refactor(abi): pass MunTypeInfo by pointer, allowing additional infor…
Browse files Browse the repository at this point in the history
…mation to be appended

Unique MunTypeInfo structs are globally allocated only once, but can be referred to in multiple places.
Depending on the TypeGroup, additional information can be appended in memory. For StructTypes, a
StructInfo struct is appended.
  • Loading branch information
Wodann committed Jan 26, 2020
1 parent 6e85fa8 commit 91e64f2
Show file tree
Hide file tree
Showing 18 changed files with 422 additions and 304 deletions.
2 changes: 1 addition & 1 deletion crates/mun_abi/c
Submodule c updated 1 files
+7 −7 include/mun_abi.h
24 changes: 12 additions & 12 deletions crates/mun_abi/src/autogen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use crate::{Privacy, TypeGroup};
#[doc = ""]
#[doc = " GUIDs are generated by taking the MD5 hash of a type's name."]
#[doc = ""]
#[doc = " <div rustbindgen derive=\"Clone\" derive=\"Copy\" derive=\"Debug\" derive=\"PartialEq\"></div>"]
#[doc = " <div rustbindgen derive=\"Clone\" derive=\"Copy\" derive=\"Debug\" derive=\"Eq\" derive=\"PartialEq\"></div>"]
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Guid {
#[doc = " 16-byte MD5 hash"]
pub b: [u8; 16usize],
Expand Down Expand Up @@ -101,7 +101,7 @@ pub struct FunctionSignature {
#[doc = " Function name"]
pub name: *const ::std::os::raw::c_char,
#[doc = " Argument types"]
pub arg_types: *const TypeInfo,
pub arg_types: *const *const TypeInfo,
#[doc = " Optional return type"]
pub return_type: *const TypeInfo,
#[doc = " Number of argument types"]
Expand Down Expand Up @@ -229,7 +229,7 @@ pub struct StructInfo {
#[doc = " Struct fields' names"]
pub field_names: *const *const ::std::os::raw::c_char,
#[doc = " Struct fields' information"]
pub field_types: *const TypeInfo,
pub field_types: *const *const TypeInfo,
#[doc = " Struct fields' offsets"]
pub field_offsets: *const u16,
#[doc = " Struct fields' sizes (in bytes)"]
Expand Down Expand Up @@ -322,10 +322,10 @@ pub struct ModuleInfo {
pub functions: *const FunctionInfo,
#[doc = " Number of module functions"]
pub num_functions: u32,
#[doc = " Module structs"]
pub structs: *const StructInfo,
#[doc = " Number of module structs"]
pub num_structs: u32,
#[doc = " Module types"]
pub types: *const *const TypeInfo,
#[doc = " Number of module types"]
pub num_types: u32,
}
#[test]
fn bindgen_test_layout_ModuleInfo() {
Expand Down Expand Up @@ -370,23 +370,23 @@ fn bindgen_test_layout_ModuleInfo() {
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).structs as *const _ as usize },
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).types as *const _ as usize },
24usize,
concat!(
"Offset of field: ",
stringify!(ModuleInfo),
"::",
stringify!(structs)
stringify!(types)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).num_structs as *const _ as usize },
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).num_types as *const _ as usize },
32usize,
concat!(
"Offset of field: ",
stringify!(ModuleInfo),
"::",
stringify!(num_structs)
stringify!(num_types)
)
);
}
Expand Down
122 changes: 96 additions & 26 deletions crates/mun_abi/src/autogen_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::prelude::*;
use std::ffi::{c_void, CStr};
use std::fmt::Formatter;
use std::marker::{Send, Sync};
use std::mem;
use std::str;
use std::{fmt, slice};

Expand All @@ -11,6 +12,19 @@ impl TypeInfo {
pub fn name(&self) -> &str {
unsafe { str::from_utf8_unchecked(CStr::from_ptr(self.name).to_bytes()) }
}

/// Retrieves the type's struct information, if available.
pub fn as_struct(&self) -> Option<&StructInfo> {
if self.group.is_struct() {
let ptr = (self as *const TypeInfo).cast::<u8>();
let ptr = ptr.wrapping_add(mem::size_of::<TypeInfo>());
let offset = ptr.align_offset(mem::align_of::<StructInfo>());
let ptr = ptr.wrapping_add(offset);
Some(unsafe { &*ptr.cast::<StructInfo>() })
} else {
None
}
}
}

impl fmt::Display for TypeInfo {
Expand Down Expand Up @@ -40,11 +54,16 @@ impl FunctionSignature {
}

/// Returns the function's arguments' types.
pub fn arg_types(&self) -> &[TypeInfo] {
pub fn arg_types(&self) -> &[&TypeInfo] {
if self.num_arg_types == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.arg_types, self.num_arg_types as usize) }
unsafe {
slice::from_raw_parts(
self.arg_types.cast::<&TypeInfo>(),
self.num_arg_types as usize,
)
}
}
}

Expand Down Expand Up @@ -97,11 +116,16 @@ impl StructInfo {
}

/// Returns the struct's field types.
pub fn field_types(&self) -> &[TypeInfo] {
pub fn field_types(&self) -> &[&TypeInfo] {
if self.num_fields == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.field_types, self.num_fields as usize) }
unsafe {
slice::from_raw_parts(
self.field_types.cast::<&TypeInfo>(),
self.num_fields as usize,
)
}
}
}

Expand Down Expand Up @@ -160,12 +184,14 @@ impl ModuleInfo {
}
}

/// Returns the module's structs.
pub fn structs(&self) -> &[StructInfo] {
if self.num_structs == 0 {
/// Returns the module's types.
pub fn types(&self) -> &[&TypeInfo] {
if self.num_types == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.structs, self.num_structs as usize) }
unsafe {
slice::from_raw_parts(self.types.cast::<&TypeInfo>(), self.num_types as usize)
}
}
}
}
Expand Down Expand Up @@ -277,6 +303,13 @@ mod tests {
use std::os::raw::c_char;
use std::ptr;

/// A dummy struct for initializing a struct's `TypeInfo`
#[allow(dead_code)]
struct StructTypeInfo {
type_info: TypeInfo,
struct_info: StructInfo,
}

fn fake_type_info(name: &CStr, group: TypeGroup) -> TypeInfo {
TypeInfo {
guid: FAKE_TYPE_GUID,
Expand All @@ -285,6 +318,13 @@ mod tests {
}
}

fn fake_struct_type_info(name: &CStr, struct_info: StructInfo) -> StructTypeInfo {
StructTypeInfo {
type_info: fake_type_info(name, TypeGroup::StructTypes),
struct_info,
}
}

const FAKE_TYPE_GUID: Guid = Guid {
b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
};
Expand All @@ -300,6 +340,28 @@ mod tests {
assert_eq!(type_info.name(), FAKE_TYPE_NAME);
}

#[test]
fn test_type_info_group_fundamental() {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
let type_group = TypeGroup::FundamentalTypes;
let type_info = fake_type_info(&type_name, type_group);

assert_eq!(type_info.group, type_group);
assert!(type_info.group.is_fundamental());
assert!(!type_info.group.is_struct());
}

#[test]
fn test_type_info_group_struct() {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
let type_group = TypeGroup::StructTypes;
let type_info = fake_type_info(&type_name, type_group);

assert_eq!(type_info.group, type_group);
assert!(type_info.group.is_struct());
assert!(!type_info.group.is_fundamental());
}

#[test]
fn test_type_info_eq() {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
Expand All @@ -310,13 +372,13 @@ mod tests {

fn fake_fn_signature(
name: &CStr,
arg_types: &[TypeInfo],
arg_types: &[&TypeInfo],
return_type: Option<&TypeInfo>,
privacy: Privacy,
) -> FunctionSignature {
FunctionSignature {
name: name.as_ptr(),
arg_types: arg_types.as_ptr(),
arg_types: arg_types.as_ptr().cast::<*const TypeInfo>(),
return_type: return_type.map_or(ptr::null(), |t| t as *const TypeInfo),
num_arg_types: arg_types.len() as u16,
privacy,
Expand Down Expand Up @@ -356,7 +418,7 @@ mod tests {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
let type_info = fake_type_info(&type_name, TypeGroup::FundamentalTypes);

let arg_types = &[type_info];
let arg_types = &[&type_info];
let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name.");
let fn_signature = fake_fn_signature(&fn_name, arg_types, None, Privacy::Public);

Expand Down Expand Up @@ -387,7 +449,7 @@ mod tests {
fn fake_struct_info(
name: &CStr,
field_names: &[*const c_char],
field_types: &[TypeInfo],
field_types: &[&TypeInfo],
field_offsets: &[u16],
field_sizes: &[u16],
) -> StructInfo {
Expand All @@ -398,7 +460,7 @@ mod tests {
StructInfo {
name: name.as_ptr(),
field_names: field_names.as_ptr(),
field_types: field_types.as_ptr(),
field_types: field_types.as_ptr().cast::<*const TypeInfo>(),
field_offsets: field_offsets.as_ptr(),
field_sizes: field_sizes.as_ptr(),
num_fields: field_names.len() as u16,
Expand Down Expand Up @@ -443,7 +505,7 @@ mod tests {
let type_info = fake_type_info(&type_name, TypeGroup::FundamentalTypes);

let field_names = &[field_name.as_ptr()];
let field_types = &[type_info];
let field_types = &[&type_info];
let field_offsets = &[1];
let field_sizes = &[2];
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
Expand All @@ -466,14 +528,14 @@ mod tests {
fn fake_module_info(
path: &CStr,
functions: &[FunctionInfo],
structs: &[StructInfo],
types: &[&TypeInfo],
) -> ModuleInfo {
ModuleInfo {
path: path.as_ptr(),
functions: functions.as_ptr(),
num_functions: functions.len() as u32,
structs: structs.as_ptr(),
num_structs: structs.len() as u32,
types: types.as_ptr().cast::<*const TypeInfo>(),
num_types: types.len() as u32,
}
}

Expand All @@ -490,12 +552,12 @@ mod tests {
#[test]
fn test_module_info_types_none() {
let functions = &[];
let structs = &[];
let types = &[];
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, functions, structs);
let module = fake_module_info(&module_path, functions, types);

assert_eq!(module.functions().len(), functions.len());
assert_eq!(module.structs().len(), structs.len());
assert_eq!(module.types().len(), types.len());
}

#[test]
Expand All @@ -515,10 +577,11 @@ mod tests {

let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name");
let struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[]);
let structs = &[struct_info];
let struct_type_info = fake_struct_type_info(&struct_name, struct_info);
let types = &[unsafe { mem::transmute(&struct_type_info) }];

let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, functions, structs);
let module = fake_module_info(&module_path, functions, types);

let result_functions = module.functions();
assert_eq!(result_functions.len(), functions.len());
Expand All @@ -530,11 +593,18 @@ mod tests {
assert_eq!(lhs.signature.privacy(), rhs.signature.privacy());
}

let result_structs = module.structs();
assert_eq!(result_structs.len(), structs.len());
for (lhs, rhs) in result_structs.iter().zip(structs.iter()) {
let result_types: &[&TypeInfo] = module.types();
assert_eq!(result_types.len(), types.len());
for (lhs, rhs) in result_types.iter().zip(types.iter()) {
assert_eq!(lhs, rhs);
assert_eq!(lhs.name(), rhs.name());
assert_eq!(lhs.field_types(), rhs.field_types());
assert_eq!(lhs.group, rhs.group);
if lhs.group == TypeGroup::StructTypes {
let lhs_struct = lhs.as_struct().unwrap();
let rhs_struct = rhs.as_struct().unwrap();
assert_eq!(lhs_struct.name(), rhs_struct.name());
assert_eq!(lhs_struct.field_types(), rhs_struct.field_types());
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/mun_codegen/src/code_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ pub fn write_module_shared_object(
// Generate the `get_info` method.
symbols::gen_reflection_ir(
db,
&target_machine,
&assembly_module,
&module.types,
&module.functions,
&module.structs,
&module.dispatch_table,
&assembly_module,
&target_machine,
);

// Optimize the assembly module
Expand Down
18 changes: 10 additions & 8 deletions crates/mun_codegen/src/code_gen/abi_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,17 @@ pub(super) fn gen_abi_types(context: ContextRef) -> AbiTypes {
false,
);

let type_info_ptr_type = type_info_type.ptr_type(AddressSpace::Const);

// Construct the `MunFunctionSignature` type
let function_signature_type = context.opaque_struct_type("struct.MunFunctionSignature");
function_signature_type.set_body(
&[
str_type.into(), // name
type_info_type.ptr_type(AddressSpace::Const).into(), // arg_types
type_info_type.ptr_type(AddressSpace::Const).into(), // return_type
context.i16_type().into(), // num_arg_types
privacy_type.into(), // privacy
str_type.into(), // name
type_info_ptr_type.ptr_type(AddressSpace::Const).into(), // arg_types
type_info_ptr_type.into(), // return_type
context.i16_type().into(), // num_arg_types
privacy_type.into(), // privacy
],
false,
);
Expand All @@ -72,7 +74,7 @@ pub(super) fn gen_abi_types(context: ContextRef) -> AbiTypes {
&[
str_type.into(), // name
str_type.ptr_type(AddressSpace::Const).into(), // field_names
type_info_type.ptr_type(AddressSpace::Const).into(), // field_types
type_info_ptr_type.ptr_type(AddressSpace::Const).into(), // field_types
context.i16_type().ptr_type(AddressSpace::Const).into(), // field_offsets
context.i16_type().ptr_type(AddressSpace::Const).into(), // field_sizes
context.i16_type().into(), // num_fields
Expand All @@ -87,8 +89,8 @@ pub(super) fn gen_abi_types(context: ContextRef) -> AbiTypes {
str_type.into(), // path
function_info_type.ptr_type(AddressSpace::Const).into(), // functions
context.i32_type().into(), // num_functions
struct_info_type.ptr_type(AddressSpace::Const).into(), // structs
context.i32_type().into(), // num_structs
type_info_ptr_type.ptr_type(AddressSpace::Const).into(), // types
context.i32_type().into(), // num_types
],
false,
);
Expand Down
Loading

0 comments on commit 91e64f2

Please sign in to comment.