From 7407966db27e58b5380719dfa5f01095fe7d1761 Mon Sep 17 00:00:00 2001 From: Wodann Date: Mon, 20 Jan 2020 16:45:34 +0100 Subject: [PATCH] refactor(abi): pass MunTypeInfo by pointer, allowing additional information 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. --- crates/mun_abi/c | 2 +- crates/mun_abi/src/autogen.rs | 24 +- crates/mun_abi/src/autogen_impl.rs | 122 ++++++-- crates/mun_codegen/src/code_gen.rs | 6 +- crates/mun_codegen/src/code_gen/abi_types.rs | 18 +- crates/mun_codegen/src/code_gen/symbols.rs | 304 ++++++++++++------- crates/mun_codegen/src/db.rs | 4 +- crates/mun_codegen/src/ir/module.rs | 45 ++- crates/mun_codegen/src/ir/ty.rs | 19 +- crates/mun_codegen/src/type_info.rs | 25 +- crates/mun_runtime/src/assembly.rs | 8 - crates/mun_runtime/src/lib.rs | 51 +--- crates/mun_runtime/src/macros.rs | 2 +- crates/mun_runtime/src/marshal.rs | 5 +- crates/mun_runtime/src/reflection.rs | 8 +- crates/mun_runtime/src/struct.rs | 25 +- crates/mun_runtime/src/test.rs | 83 ++--- crates/mun_runtime_capi/ffi | 2 +- 18 files changed, 449 insertions(+), 304 deletions(-) diff --git a/crates/mun_abi/c b/crates/mun_abi/c index fbcc74d0e..75d941290 160000 --- a/crates/mun_abi/c +++ b/crates/mun_abi/c @@ -1 +1 @@ -Subproject commit fbcc74d0e4971c82955a7959d9dc5fda8208e578 +Subproject commit 75d9412905ed5cc2f9842148d5ce6d4da9493b91 diff --git a/crates/mun_abi/src/autogen.rs b/crates/mun_abi/src/autogen.rs index 1e8522ad5..bd4dd33a1 100644 --- a/crates/mun_abi/src/autogen.rs +++ b/crates/mun_abi/src/autogen.rs @@ -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 = "
"] +#[doc = "
"] #[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], @@ -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"] @@ -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)"] @@ -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() { @@ -370,23 +370,23 @@ fn bindgen_test_layout_ModuleInfo() { ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::())).structs as *const _ as usize }, + unsafe { &(*(::std::ptr::null::())).types as *const _ as usize }, 24usize, concat!( "Offset of field: ", stringify!(ModuleInfo), "::", - stringify!(structs) + stringify!(types) ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::())).num_structs as *const _ as usize }, + unsafe { &(*(::std::ptr::null::())).num_types as *const _ as usize }, 32usize, concat!( "Offset of field: ", stringify!(ModuleInfo), "::", - stringify!(num_structs) + stringify!(num_types) ) ); } diff --git a/crates/mun_abi/src/autogen_impl.rs b/crates/mun_abi/src/autogen_impl.rs index 252b671d7..1db879dba 100644 --- a/crates/mun_abi/src/autogen_impl.rs +++ b/crates/mun_abi/src/autogen_impl.rs @@ -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}; @@ -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::(); + let ptr = ptr.wrapping_add(mem::size_of::()); + let offset = ptr.align_offset(mem::align_of::()); + let ptr = ptr.wrapping_add(offset); + Some(unsafe { &*ptr.cast::() }) + } else { + None + } + } } impl fmt::Display for TypeInfo { @@ -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, + ) + } } } @@ -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, + ) + } } } @@ -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) + } } } } @@ -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, @@ -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], }; @@ -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."); @@ -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, @@ -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); @@ -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 { @@ -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, @@ -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."); @@ -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, } } @@ -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] @@ -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()); @@ -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()); + } } } diff --git a/crates/mun_codegen/src/code_gen.rs b/crates/mun_codegen/src/code_gen.rs index 29994f442..f4e5c5804 100644 --- a/crates/mun_codegen/src/code_gen.rs +++ b/crates/mun_codegen/src/code_gen.rs @@ -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 diff --git a/crates/mun_codegen/src/code_gen/abi_types.rs b/crates/mun_codegen/src/code_gen/abi_types.rs index 0e158018e..380191c4e 100644 --- a/crates/mun_codegen/src/code_gen/abi_types.rs +++ b/crates/mun_codegen/src/code_gen/abi_types.rs @@ -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, ); @@ -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 @@ -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, ); diff --git a/crates/mun_codegen/src/code_gen/symbols.rs b/crates/mun_codegen/src/code_gen/symbols.rs index cb3245893..cbd25d6d1 100644 --- a/crates/mun_codegen/src/code_gen/symbols.rs +++ b/crates/mun_codegen/src/code_gen/symbols.rs @@ -1,47 +1,65 @@ use super::abi_types::{gen_abi_types, AbiTypes}; -use crate::ir::dispatch_table::{DispatchTable, DispatchableFunction}; -use crate::ir::function; -use crate::type_info::TypeInfo; +use crate::ir::{ + dispatch_table::{DispatchTable, DispatchableFunction}, + function, +}; +use crate::type_info::{TypeGroup, TypeInfo}; use crate::values::{BasicValue, GlobalValue}; use crate::IrDatabase; -use abi::TypeGroup; -use hir::{Ty, TypeCtor}; +use hir::Ty; use inkwell::{ attributes::Attribute, module::{Linkage, Module}, targets::TargetMachine, - types::StructType, values::{FunctionValue, IntValue, PointerValue, StructValue, UnnamedAddress}, AddressSpace, }; -use std::collections::HashMap; - -pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo { - match ty { - Ty::Apply(ctor) => match ctor.ctor { - TypeCtor::Float => TypeInfo::new("@core::float", TypeGroup::FundamentalTypes), - TypeCtor::Int => TypeInfo::new("@core::int", TypeGroup::FundamentalTypes), - TypeCtor::Bool => TypeInfo::new("@core::bool", TypeGroup::FundamentalTypes), - TypeCtor::Struct(s) => TypeInfo::new(s.name(db).to_string(), TypeGroup::StructTypes), - _ => unreachable!("{:?} unhandled", ctor), - }, - _ => unreachable!(), - } -} +use std::collections::{HashMap, HashSet}; /// Construct an IR `MunTypeInfo` struct value for the specified `TypeInfo` -fn type_info_ir(ty: &TypeInfo, module: &Module) -> StructValue { - let context = module.get_context(); - let guid_values: [IntValue; 16] = - array_init::array_init(|i| context.i8_type().const_int(u64::from(ty.guid[i]), false)); - context.const_struct( - &[ - context.i8_type().const_array(&guid_values).into(), - intern_string(module, &ty.name).into(), - context.i8_type().const_int(ty.group as u64, false).into(), - ], - false, - ) +fn type_info_ir( + db: &D, + target: &TargetMachine, + module: &Module, + types: &AbiTypes, + global_type_info_lookup_table: &mut HashMap, + type_info: TypeInfo, +) -> PointerValue { + if let Some(value) = global_type_info_lookup_table.get(&type_info) { + *value + } else { + let context = module.get_context(); + let guid_values: [IntValue; 16] = array_init::array_init(|i| { + context + .i8_type() + .const_int(u64::from(type_info.guid.b[i]), false) + }); + + let type_info_ir = context.const_struct( + &[ + context.i8_type().const_array(&guid_values).into(), + intern_string(module, &type_info.name).into(), + context + .i8_type() + .const_int(type_info.group.clone().into(), false) + .into(), + ], + false, + ); + + let type_info_ir = match type_info.group { + TypeGroup::FundamentalTypes => type_info_ir, + TypeGroup::StructTypes(s) => { + let struct_info_ir = + gen_struct_info(db, target, module, types, global_type_info_lookup_table, s); + context.const_struct(&[type_info_ir.into(), struct_info_ir.into()], false) + } + }; + + let type_info_ir = gen_global(module, &type_info_ir, "").as_pointer_value(); + global_type_info_lookup_table.insert(type_info, type_info_ir); + type_info_ir + } } /// Intern a string by constructing a global value. Looks something like this: @@ -58,6 +76,7 @@ fn gen_signature_from_function( db: &D, module: &Module, types: &AbiTypes, + global_type_info_lookup_table: &HashMap, function: hir::Function, ) -> StructValue { let name_str = intern_string(&module, &function.name(db).to_string()); @@ -65,13 +84,19 @@ fn gen_signature_from_function( hir::Visibility::Public => 0, _ => 1, }; - let fn_sig = function.ty(db).callable_sig(db).unwrap(); - let ret_type_ir = gen_signature_return_type(db, module, types, fn_sig.ret().clone()); - let params_type_ir = gen_type_info_array( + let fn_sig = function.ty(db).callable_sig(db).unwrap(); + let ret_type_ir = gen_signature_return_type( db, + types, + global_type_info_lookup_table, + fn_sig.ret().clone(), + ); + + let params_type_ir = gen_type_info_ptr_array( module, types, + global_type_info_lookup_table, fn_sig.params().iter().map(|ty| db.type_info(ty.clone())), ); let num_params = fn_sig.params().len(); @@ -94,6 +119,7 @@ fn gen_signature_from_dispatch_entry( db: &D, module: &Module, types: &AbiTypes, + global_type_info_lookup_table: &HashMap, function: &DispatchableFunction, ) -> StructValue { let name_str = intern_string(&module, &function.prototype.name); @@ -103,14 +129,14 @@ fn gen_signature_from_dispatch_entry( // }; let ret_type_ir = gen_signature_return_type_from_type_info( db, - module, types, + global_type_info_lookup_table, function.prototype.ret_type.clone(), ); - let params_type_ir = gen_type_info_array( - db, + let params_type_ir = gen_type_info_ptr_array( module, types, + global_type_info_lookup_table, function.prototype.arg_types.iter().cloned(), ); let num_params = function.prototype.arg_types.len(); @@ -128,11 +154,13 @@ fn gen_signature_from_dispatch_entry( ]) } -/// Generates an array of TypeInfo's -fn gen_type_info_array( - _db: &D, +/// Recursively expands an array of TypeInfo into an array of IR pointers +fn expand_type_info( + db: &D, + target: &TargetMachine, module: &Module, types: &AbiTypes, + global_type_info_lookup_table: &mut HashMap, hir_types: impl Iterator, ) -> PointerValue { let mut hir_types = hir_types.peekable(); @@ -140,13 +168,46 @@ fn gen_type_info_array( types .type_info_type .ptr_type(AddressSpace::Const) + .ptr_type(AddressSpace::Const) .const_null() } else { let type_infos = hir_types - .map(|ty| type_info_ir(&ty, &module)) - .collect::>(); + .map(|ty| type_info_ir(db, target, module, types, global_type_info_lookup_table, ty)) + .collect::>(); + + let type_array_ir = types + .type_info_type + .ptr_type(AddressSpace::Const) + .const_array(&type_infos); + + gen_global(module, &type_array_ir, "").as_pointer_value() + } +} + +/// Generates IR for an array of TypeInfo values +fn gen_type_info_ptr_array( + module: &Module, + types: &AbiTypes, + global_type_info_lookup_table: &HashMap, + hir_types: impl Iterator, +) -> PointerValue { + let mut hir_types = hir_types.peekable(); + if hir_types.peek().is_none() { + types + .type_info_type + .ptr_type(AddressSpace::Const) + .ptr_type(AddressSpace::Const) + .const_null() + } else { + let type_infos = hir_types + .map(|ty| *global_type_info_lookup_table.get(&ty).unwrap()) + .collect::>(); + + let type_array_ir = types + .type_info_type + .ptr_type(AddressSpace::Const) + .const_array(&type_infos); - let type_array_ir = types.type_info_type.const_array(&type_infos); gen_global(module, &type_array_ir, "").as_pointer_value() } } @@ -155,14 +216,14 @@ fn gen_type_info_array( /// of the function; or `null` if the return type is empty. fn gen_signature_return_type( db: &D, - module: &Module, types: &AbiTypes, + global_type_info_lookup_table: &HashMap, ret_type: Ty, ) -> PointerValue { gen_signature_return_type_from_type_info( db, - module, types, + global_type_info_lookup_table, if ret_type.is_empty() { None } else { @@ -175,13 +236,12 @@ fn gen_signature_return_type( /// of the function; or `null` if the return type is empty. fn gen_signature_return_type_from_type_info( _db: &D, - module: &Module, types: &AbiTypes, + global_type_info_lookup_table: &HashMap, ret_type: Option, ) -> PointerValue { if let Some(ret_type) = ret_type { - let ret_type_const = type_info_ir(&ret_type, &module); - gen_global(module, &ret_type_const, "").as_pointer_value() + *global_type_info_lookup_table.get(&ret_type).unwrap() } else { types .type_info_type @@ -194,8 +254,9 @@ fn gen_signature_return_type_from_type_info( /// MunFunctionInfo[] info = { ... } fn gen_function_info_array<'a, D: IrDatabase>( db: &D, - types: &AbiTypes, module: &Module, + types: &AbiTypes, + global_type_info_lookup_table: &HashMap, functions: impl Iterator, ) -> GlobalValue { let function_infos: Vec = functions @@ -207,7 +268,8 @@ fn gen_function_info_array<'a, D: IrDatabase>( value.set_linkage(Linkage::Private); // Generate the signature from the function - let signature = gen_signature_from_function(db, module, types, *f); + let signature = + gen_signature_from_function(db, module, types, global_type_info_lookup_table, *f); // Generate the function info value types.function_info_type.const_named_struct(&[ @@ -222,56 +284,52 @@ fn gen_function_info_array<'a, D: IrDatabase>( /// Construct a global that holds a reference to all structs. e.g.: /// MunStructInfo[] info = { ... } -fn gen_struct_info_array<'a, D: IrDatabase>( +fn gen_struct_info( db: &D, - types: &AbiTypes, - module: &Module, target: &TargetMachine, - structs: impl Iterator, -) -> GlobalValue { - let target_data = target.get_target_data(); - let struct_infos: Vec = structs - .map(|(s, t)| { - let name_str = intern_string(&module, &s.name(db).to_string()); + module: &Module, + types: &AbiTypes, + global_type_info_lookup_table: &mut HashMap, + s: hir::Struct, +) -> StructValue { + let name_str = intern_string(&module, &s.name(db).to_string()); - let fields = s.fields(db); + let fields = s.fields(db); + let field_names = fields.iter().map(|field| field.name(db).to_string()); + let (field_names, num_fields) = gen_string_array(module, field_names); - let field_names = fields.iter().map(|field| field.name(db).to_string()); - let (field_names, num_fields) = gen_string_array(module, field_names); + let field_types = expand_type_info( + db, + target, + module, + types, + global_type_info_lookup_table, + fields.iter().map(|field| db.type_info(field.ty(db))), + ); - let field_types = gen_type_info_array( - db, - module, - types, - fields.iter().map(|field| db.type_info(field.ty(db))), - ); - - let field_offsets = - (0..fields.len()).map(|idx| target_data.offset_of_element(t, idx as u32).unwrap()); - let (field_offsets, _) = gen_u16_array(module, field_offsets); - - let field_sizes = fields - .iter() - .map(|field| target_data.get_store_size(&db.type_ir(field.ty(db)))); - let (field_sizes, _) = gen_u16_array(module, field_sizes); - - types.struct_info_type.const_named_struct(&[ - name_str.into(), - field_names.into(), - field_types.into(), - field_offsets.into(), - field_sizes.into(), - module - .get_context() - .i16_type() - .const_int(num_fields as u64, false) - .into(), - ]) - }) - .collect(); + let target_data = target.get_target_data(); + let t = db.struct_ty(s); + let field_offsets = + (0..fields.len()).map(|idx| target_data.offset_of_element(&t, idx as u32).unwrap()); + let (field_offsets, _) = gen_u16_array(module, field_offsets); + + let field_sizes = fields + .iter() + .map(|field| target_data.get_store_size(&db.type_ir(field.ty(db)))); + let (field_sizes, _) = gen_u16_array(module, field_sizes); - let struct_infos = types.struct_info_type.const_array(&struct_infos); - gen_global(module, &struct_infos, "fn.get_info.structs") + types.struct_info_type.const_named_struct(&[ + name_str.into(), + field_names.into(), + field_types.into(), + field_offsets.into(), + field_sizes.into(), + module + .get_context() + .i16_type() + .const_int(num_fields as u64, false) + .into(), + ]) } /// Constructs a global from the specified list of strings @@ -333,15 +391,24 @@ fn gen_global(module: &Module, value: &dyn BasicValue, name: &str) -> GlobalValu /// ``` fn gen_dispatch_table( db: &D, - types: &AbiTypes, module: &Module, + types: &AbiTypes, + global_type_info_lookup_table: &HashMap, dispatch_table: &DispatchTable, ) -> StructValue { // Generate a vector with all the function signatures let signatures: Vec = dispatch_table .entries() .iter() - .map(|entry| gen_signature_from_dispatch_entry(db, module, types, entry)) + .map(|entry| { + gen_signature_from_dispatch_entry( + db, + module, + types, + global_type_info_lookup_table, + entry, + ) + }) .collect(); // Construct an IR array from the signatures @@ -386,38 +453,59 @@ fn gen_dispatch_table( /// for the ABI that `get_info` exposes. pub(super) fn gen_reflection_ir( db: &impl IrDatabase, + target: &TargetMachine, + module: &Module, + types: &HashSet, function_map: &HashMap, - struct_map: &HashMap, dispatch_table: &DispatchTable, - module: &Module, - target: &TargetMachine, ) { // Get all the types let abi_types = gen_abi_types(module.get_context()); + let mut global_type_info_lookup_table = HashMap::new(); + let num_types = types.len(); + let types = expand_type_info( + db, + target, + module, + &abi_types, + &mut global_type_info_lookup_table, + types.iter().cloned(), + ); + // Construct the module info struct let module_info = abi_types.module_info_type.const_named_struct(&[ intern_string(module, "").into(), - gen_function_info_array(db, &abi_types, module, function_map.iter()) - .as_pointer_value() - .into(), + gen_function_info_array( + db, + module, + &abi_types, + &global_type_info_lookup_table, + function_map.iter(), + ) + .as_pointer_value() + .into(), module .get_context() .i32_type() .const_int(function_map.len() as u64, false) .into(), - gen_struct_info_array(db, &abi_types, module, target, struct_map.iter()) - .as_pointer_value() - .into(), + types.into(), module .get_context() .i32_type() - .const_int(struct_map.len() as u64, false) + .const_int(num_types as u64, false) .into(), ]); // Construct the dispatch table struct - let dispatch_table = gen_dispatch_table(db, &abi_types, module, dispatch_table); + let dispatch_table = gen_dispatch_table( + db, + module, + &abi_types, + &global_type_info_lookup_table, + dispatch_table, + ); // Construct the actual `get_info` function gen_get_info_fn(db, module, &abi_types, module_info, dispatch_table); diff --git a/crates/mun_codegen/src/db.rs b/crates/mun_codegen/src/db.rs index 4bf7149c5..5b911aebd 100644 --- a/crates/mun_codegen/src/db.rs +++ b/crates/mun_codegen/src/db.rs @@ -1,7 +1,5 @@ #![allow(clippy::type_repetition_in_bounds)] - - use crate::{ir::module::ModuleIR, type_info::TypeInfo, Context}; use inkwell::types::StructType; use inkwell::{types::AnyTypeEnum, OptimizationLevel}; @@ -37,6 +35,6 @@ pub trait IrDatabase: hir::HirDatabase { fn module_ir(&self, file: hir::FileId) -> Arc; /// Given a type, return the runtime `TypeInfo` that can be used to reflect the type. - #[salsa::invoke(crate::code_gen::symbols::type_info_query)] + #[salsa::invoke(crate::ir::ty::type_info_query)] fn type_info(&self, ty: hir::Ty) -> TypeInfo; } diff --git a/crates/mun_codegen/src/ir/module.rs b/crates/mun_codegen/src/ir/module.rs index 37f98d869..d3d54578a 100644 --- a/crates/mun_codegen/src/ir/module.rs +++ b/crates/mun_codegen/src/ir/module.rs @@ -1,9 +1,11 @@ +use super::adt; use crate::ir::dispatch_table::{DispatchTable, DispatchTableBuilder}; -use crate::ir::{adt, function}; +use crate::ir::function; +use crate::type_info::TypeInfo; use crate::IrDatabase; use hir::{FileId, ModuleDef}; -use inkwell::{module::Module, types::StructType, values::FunctionValue}; -use std::collections::HashMap; +use inkwell::{module::Module, values::FunctionValue}; +use std::collections::{HashMap, HashSet}; use std::sync::Arc; #[derive(Debug, Clone, Eq, PartialEq)] @@ -17,8 +19,8 @@ pub struct ModuleIR { /// A mapping from HIR functions to LLVM IR values pub functions: HashMap, - /// A mapping from HIR structs to LLVM IR types - pub structs: HashMap, + /// A set of unique TypeInfo values + pub types: HashSet, /// The dispatch table pub dispatch_table: DispatchTable, @@ -30,12 +32,14 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc { .context() .create_module(db.file_relative_path(file_id).as_str()); - // Generate all type definitions - let mut structs = HashMap::new(); + // Collect type definitions for all used types + let mut types = HashSet::new(); + for def in db.module_data(file_id).definitions() { match def { ModuleDef::Struct(s) => { - structs.insert(*s, adt::gen_struct_decl(db, *s)); + let _t = adt::gen_struct_decl(db, *s); + types.insert(db.type_info(s.ty(db))); } ModuleDef::BuiltinType(_) | ModuleDef::Function(_) => (), } @@ -49,6 +53,17 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc { #[allow(clippy::single_match)] match def { ModuleDef::Function(f) => { + // Collect argument types + let fn_sig = f.ty(db).callable_sig(db).unwrap(); + for ty in fn_sig.params().iter() { + types.insert(db.type_info(ty.clone())); + } + // Collect return type + let ret_ty = fn_sig.ret(); + if !ret_ty.is_empty() { + types.insert(db.type_info(ret_ty.clone())); + } + // Construct the function signature let fun = function::gen_signature(db, *f, &llvm_module); functions.insert(*f, fun); @@ -79,11 +94,23 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc { fn_pass_manager.run_on(llvm_function); } + // Dispatch entries can include previously unchecked intrinsics + for entry in dispatch_table.entries().iter() { + // Collect argument types + for ty in entry.prototype.arg_types.iter() { + types.insert(ty.clone()); + } + // Collect return type + if let Some(ret_ty) = entry.prototype.ret_type.as_ref() { + types.insert(ret_ty.clone()); + } + } + Arc::new(ModuleIR { file_id, llvm_module, functions, - structs, + types, dispatch_table, }) } diff --git a/crates/mun_codegen/src/ir/ty.rs b/crates/mun_codegen/src/ir/ty.rs index dace7496e..21542ed08 100644 --- a/crates/mun_codegen/src/ir/ty.rs +++ b/crates/mun_codegen/src/ir/ty.rs @@ -1,5 +1,8 @@ use super::try_convert_any_to_basic; -use crate::IrDatabase; +use crate::{ + type_info::{TypeGroup, TypeInfo}, + IrDatabase, +}; use hir::{ApplicationTy, CallableDef, Ty, TypeCtor}; use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum, StructType}; use inkwell::AddressSpace; @@ -48,3 +51,17 @@ pub fn struct_ty_query(db: &impl IrDatabase, s: hir::Struct) -> StructType { let name = s.name(db).to_string(); db.context().opaque_struct_type(&name) } + +/// Constructs the `TypeInfo` for the specified HIR type +pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo { + match ty { + Ty::Apply(ctor) => match ctor.ctor { + TypeCtor::Float => TypeInfo::new("core::float", TypeGroup::FundamentalTypes), + TypeCtor::Int => TypeInfo::new("core::int", TypeGroup::FundamentalTypes), + TypeCtor::Bool => TypeInfo::new("core::bool", TypeGroup::FundamentalTypes), + TypeCtor::Struct(s) => TypeInfo::new(s.name(db).to_string(), TypeGroup::StructTypes(s)), + _ => unreachable!("{:?} unhandled", ctor), + }, + _ => unreachable!("{:?} unhandled", ty), + } +} diff --git a/crates/mun_codegen/src/type_info.rs b/crates/mun_codegen/src/type_info.rs index 17f2ee66e..b56db2521 100644 --- a/crates/mun_codegen/src/type_info.rs +++ b/crates/mun_codegen/src/type_info.rs @@ -1,9 +1,22 @@ -use abi::TypeGroup; +use abi::Guid; use std::hash::{Hash, Hasher}; -pub type Guid = [u8; 16]; +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum TypeGroup { + FundamentalTypes, + StructTypes(hir::Struct), +} + +impl From for u64 { + fn from(group: TypeGroup) -> Self { + match group { + TypeGroup::FundamentalTypes => 0, + TypeGroup::StructTypes(_) => 1, + } + } +} -#[derive(Clone, Eq, Ord, PartialOrd, Debug)] +#[derive(Clone, Eq, Debug)] pub struct TypeInfo { pub guid: Guid, pub name: String, @@ -12,7 +25,7 @@ pub struct TypeInfo { impl Hash for TypeInfo { fn hash(&self, state: &mut H) { - state.write(&self.guid) + state.write(&self.guid.b) } } @@ -26,7 +39,9 @@ impl TypeInfo { pub fn new>(name: S, group: TypeGroup) -> TypeInfo { TypeInfo { name: name.as_ref().to_string(), - guid: md5::compute(name.as_ref()).0, + guid: Guid { + b: md5::compute(name.as_ref()).0, + }, group, } } diff --git a/crates/mun_runtime/src/assembly.rs b/crates/mun_runtime/src/assembly.rs index ab2c3a8d6..a8b4d77d1 100644 --- a/crates/mun_runtime/src/assembly.rs +++ b/crates/mun_runtime/src/assembly.rs @@ -35,10 +35,6 @@ impl Assembly { runtime_dispatch_table.insert_fn(function.signature.name(), function.clone()); } - for s in info.symbols.structs() { - runtime_dispatch_table.insert_struct(s.name(), s.clone()); - } - Ok(Assembly { library_path: library_path.to_path_buf(), library: Some(library), @@ -76,10 +72,6 @@ impl Assembly { runtime_dispatch_table.remove_fn(function.signature.name()); } - for s in self.info.symbols.structs() { - runtime_dispatch_table.remove_struct(s.name()); - } - // Drop the old library, as some operating systems don't allow editing of in-use shared // libraries self.library.take(); diff --git a/crates/mun_runtime/src/lib.rs b/crates/mun_runtime/src/lib.rs index 7052efb83..c22559d6d 100644 --- a/crates/mun_runtime/src/lib.rs +++ b/crates/mun_runtime/src/lib.rs @@ -22,7 +22,7 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc::{channel, Receiver}; use std::time::Duration; -use abi::{FunctionInfo, FunctionSignature, Guid, Privacy, StructInfo, TypeGroup, TypeInfo}; +use abi::{FunctionInfo, FunctionSignature, Guid, Privacy, TypeGroup, TypeInfo}; use failure::Error; use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; @@ -73,7 +73,6 @@ impl RuntimeBuilder { #[derive(Default)] pub struct DispatchTable { functions: HashMap, - structs: HashMap, } impl DispatchTable { @@ -98,28 +97,6 @@ impl DispatchTable { pub fn remove_fn>(&mut self, fn_path: T) -> Option { self.functions.remove(fn_path.as_ref()) } - - /// Retrieves the [`StructInfo`] corresponding to `struct_path`, if it exists. - pub fn get_struct>(&self, struct_path: T) -> Option<&StructInfo> { - self.structs.get(struct_path.as_ref()) - } - - /// Inserts the `struct_info` for `struct_path` into the dispatch table. - /// - /// If the dispatch table already contained this `struct_path`, the value is updated, and the - /// old value is returned. - pub fn insert_struct( - &mut self, - struct_path: T, - struct_info: StructInfo, - ) -> Option { - self.structs.insert(struct_path.to_string(), struct_info) - } - - /// Removes and returns the `struct_info` corresponding to `struct_path`, if it exists. - pub fn remove_struct>(&mut self, struct_path: T) -> Option { - self.structs.remove(struct_path.as_ref()) - } } /// A runtime for the Mun language. @@ -132,7 +109,7 @@ pub struct Runtime { _name: CString, _u64_type: CString, _ptr_mut_u8_type: CString, - _arg_types: Vec, + _arg_types: Vec<*mut abi::TypeInfo>, _ret_type: Box, } @@ -154,20 +131,20 @@ impl Runtime { let ptr_mut_u8_type = CString::new("core::u8*").unwrap(); let arg_types = vec![ - TypeInfo { + Box::into_raw(Box::new(TypeInfo { guid: Guid { b: md5::compute("core::u64").0, }, name: u64_type.as_ptr(), group: TypeGroup::FundamentalTypes, - }, - TypeInfo { + })), + Box::into_raw(Box::new(TypeInfo { guid: Guid { b: md5::compute("core::u64").0, }, name: u64_type.as_ptr(), group: TypeGroup::FundamentalTypes, - }, + })), ]; let ret_type = Box::new(TypeInfo { @@ -181,7 +158,7 @@ impl Runtime { let fn_info = FunctionInfo { signature: FunctionSignature { name: name.as_ptr(), - arg_types: arg_types.as_ptr(), + arg_types: arg_types.as_ptr() as *const *const _, return_type: ret_type.as_ref(), num_arg_types: 2, privacy: Privacy::Public, @@ -239,11 +216,6 @@ impl Runtime { self.dispatch_table.get_fn(function_name) } - /// Retrieves the struct information corresponding to `struct_name`, if available. - pub fn get_struct_info(&self, struct_name: &str) -> Option<&StructInfo> { - self.dispatch_table.get_struct(struct_name) - } - /// Updates the state of the runtime. This includes checking for file changes, and reloading /// compiled assemblies. pub fn update(&mut self) -> bool { @@ -270,6 +242,15 @@ impl Runtime { } } +impl Drop for Runtime { + fn drop(&mut self) { + for raw_arg_type in self._arg_types.iter() { + // Drop arg type memory + let _arg_type = unsafe { Box::from_raw(*raw_arg_type) }; + } + } +} + /// Extends a result object with functions that allow retrying of an action. pub trait RetryResultExt: Sized { /// Output type on success diff --git a/crates/mun_runtime/src/macros.rs b/crates/mun_runtime/src/macros.rs index 39842b3a8..724d95d83 100644 --- a/crates/mun_runtime/src/macros.rs +++ b/crates/mun_runtime/src/macros.rs @@ -162,7 +162,7 @@ macro_rules! invoke_fn_impl { let result = function($($Arg.marshal()),*); // Marshall the result - Ok(result.marshal_into(runtime, function_info.signature.return_type())) + Ok(result.marshal_into(function_info.signature.return_type())) } Err(e) => Err($ErrName::new(e, runtime, function_name, $($Arg),*)) } diff --git a/crates/mun_runtime/src/marshal.rs b/crates/mun_runtime/src/marshal.rs index e83c83bfb..889fa42cd 100644 --- a/crates/mun_runtime/src/marshal.rs +++ b/crates/mun_runtime/src/marshal.rs @@ -1,4 +1,3 @@ -use crate::Runtime; use abi::TypeInfo; /// Used to do value-to-value conversions that require runtime type information while consuming the @@ -7,11 +6,11 @@ use abi::TypeInfo; /// If no `TypeInfo` is provided, the type is `()`. pub trait MarshalInto: Sized { /// Performs the conversion. - fn marshal_into(self, runtime: &Runtime, type_info: Option<&TypeInfo>) -> T; + fn marshal_into(self, type_info: Option<&TypeInfo>) -> T; } impl MarshalInto for T { - fn marshal_into(self, _runtime: &Runtime, _type_info: Option<&TypeInfo>) -> T { + fn marshal_into(self, _type_info: Option<&TypeInfo>) -> T { self } } diff --git a/crates/mun_runtime/src/reflection.rs b/crates/mun_runtime/src/reflection.rs index af8436545..3df68c571 100644 --- a/crates/mun_runtime/src/reflection.rs +++ b/crates/mun_runtime/src/reflection.rs @@ -89,7 +89,7 @@ impl ReturnTypeReflection for f64 { type Marshalled = f64; fn type_name() -> &'static str { - "@core::float" + "core::float" } } @@ -97,7 +97,7 @@ impl ReturnTypeReflection for i64 { type Marshalled = i64; fn type_name() -> &'static str { - "@core::int" + "core::int" } } @@ -105,7 +105,7 @@ impl ReturnTypeReflection for bool { type Marshalled = bool; fn type_name() -> &'static str { - "@core::bool" + "core::bool" } } @@ -113,6 +113,6 @@ impl ReturnTypeReflection for () { type Marshalled = (); fn type_name() -> &'static str { - "@core::empty" + "core::empty" } } diff --git a/crates/mun_runtime/src/struct.rs b/crates/mun_runtime/src/struct.rs index 717a84282..1472754f0 100644 --- a/crates/mun_runtime/src/struct.rs +++ b/crates/mun_runtime/src/struct.rs @@ -1,7 +1,6 @@ use crate::{ marshal::MarshalInto, reflection::{ArgumentReflection, ReturnTypeReflection}, - Runtime, }; use abi::{StructInfo, TypeInfo}; use std::mem; @@ -23,18 +22,15 @@ pub struct Struct { impl Struct { /// Creates a struct that wraps a raw Mun struct. - pub fn new(runtime: &Runtime, type_info: &TypeInfo, raw: RawStruct) -> Result { - let struct_info = runtime.get_struct_info(type_info.name()).ok_or_else(|| { - format!( - "Could not find information for struct `{}`.", - type_info.name() - ) - })?; - - Ok(Self { + /// + /// The provided [`TypeInfo`] must be for a struct type. + fn new(type_info: &TypeInfo, raw: RawStruct) -> Self { + assert!(type_info.group.is_struct()); + + Self { raw, - info: struct_info.clone(), - }) + info: type_info.as_struct().unwrap().clone(), + } } /// Consumes the `Struct`, returning a raw Mun struct. @@ -177,9 +173,8 @@ impl ReturnTypeReflection for Struct { } impl MarshalInto for RawStruct { - fn marshal_into(self, runtime: &Runtime, type_info: Option<&TypeInfo>) -> Struct { + fn marshal_into(self, type_info: Option<&TypeInfo>) -> Struct { // `type_info` is only `None` for the `()` type - // the `StructInfo` for this type must have been loaded for a function to return its type - Struct::new(runtime, type_info.unwrap(), self).unwrap() + Struct::new(type_info.unwrap(), self) } } diff --git a/crates/mun_runtime/src/test.rs b/crates/mun_runtime/src/test.rs index 380823205..b6996a108 100644 --- a/crates/mun_runtime/src/test.rs +++ b/crates/mun_runtime/src/test.rs @@ -304,31 +304,16 @@ fn compiler_valid_utf8() { use std::ffi::CStr; use std::slice; - let mut driver = TestDriver::new( + let driver = TestDriver::new( r#" struct Foo { a: int, } - fn foo(n:int):bool { false } + fn foo(n:Foo):bool { false } "#, ); - let foo_struct = driver.runtime.get_struct_info("Foo").unwrap(); - assert_eq!( - unsafe { CStr::from_ptr(foo_struct.name) }.to_str().is_ok(), - true - ); - - let field_names = - unsafe { slice::from_raw_parts(foo_struct.field_names, foo_struct.num_fields as usize) }; - for field_name in field_names { - assert_eq!( - unsafe { CStr::from_ptr(*field_name) }.to_str().is_ok(), - true - ); - } - let foo_func = driver.runtime.get_function_info("foo").unwrap(); assert_eq!( unsafe { CStr::from_ptr(foo_func.signature.name) } @@ -336,57 +321,33 @@ fn compiler_valid_utf8() { .is_ok(), true ); - assert_eq!( - unsafe { CStr::from_ptr((*foo_func.signature.arg_types).name) } - .to_str() - .is_ok(), - true - ); - assert_eq!( - unsafe { CStr::from_ptr((*foo_func.signature.return_type).name) } - .to_str() - .is_ok(), - true - ); - - assert_invoke_eq!(bool, false, driver, "foo", 10i64); -} - -#[test] -fn struct_info() { - use crate::ReturnTypeReflection; - use abi::Guid; - let driver = TestDriver::new( - r" - struct Foo; - struct Bar(bool); - struct Baz { a: int, b: float }; - ", - ); + for arg_type in foo_func.signature.arg_types() { + assert_eq!( + unsafe { CStr::from_ptr(arg_type.name) }.to_str().is_ok(), + true + ); - assert_struct_info_eq(&driver, "Foo", &[]); - assert_struct_info_eq(&driver, "Bar", &[bool::type_guid()]); - assert_struct_info_eq(&driver, "Baz", &[i64::type_guid(), f64::type_guid()]); + if let Some(s) = arg_type.as_struct() { + assert_eq!(unsafe { CStr::from_ptr(s.name) }.to_str().is_ok(), true); - fn assert_struct_info_eq( - driver: &TestDriver, - expected_name: &str, - expected_field_types: &[Guid], - ) { - let struct_info = driver.runtime.get_struct_info(expected_name).unwrap(); + let field_names = + unsafe { slice::from_raw_parts(s.field_names, s.num_fields as usize) }; - assert_eq!(struct_info.name(), expected_name); - if expected_field_types.is_empty() { - assert_eq!(struct_info.field_types(), &[]); - } else { - let field_types = struct_info.field_types(); - assert_eq!(field_types.len(), expected_field_types.len()); - for (idx, field_type) in expected_field_types.iter().enumerate() { - assert_eq!(field_types[idx].guid, *field_type); + for field_name in field_names { + assert_eq!( + unsafe { CStr::from_ptr(*field_name) }.to_str().is_ok(), + true + ); } } } + assert_eq!( + unsafe { CStr::from_ptr((*foo_func.signature.return_type).name) } + .to_str() + .is_ok(), + true + ); } #[test] diff --git a/crates/mun_runtime_capi/ffi b/crates/mun_runtime_capi/ffi index fdacb0bee..6b183bc36 160000 --- a/crates/mun_runtime_capi/ffi +++ b/crates/mun_runtime_capi/ffi @@ -1 +1 @@ -Subproject commit fdacb0beed06b02bf4576e255f222190f3c77acf +Subproject commit 6b183bc3615d6cf56b18538f171bf975b7d2eb0c