Skip to content

Commit

Permalink
Merge pull request #64 from mun-lang/feature/structs
Browse files Browse the repository at this point in the history
Adds data structures
  • Loading branch information
baszalmstra authored Jan 11, 2020
2 parents ef40798 + a2c7ce7 commit 267f3c3
Show file tree
Hide file tree
Showing 77 changed files with 4,506 additions and 446 deletions.
1 change: 1 addition & 0 deletions crates/mun/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/
8 changes: 0 additions & 8 deletions crates/mun/test/main.mun

This file was deleted.

2 changes: 1 addition & 1 deletion crates/mun_abi/c
Submodule c updated 1 files
+22 −0 include/mun_abi.h
90 changes: 85 additions & 5 deletions crates/mun_abi/src/autogen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,62 @@ fn bindgen_test_layout_FunctionInfo() {
)
);
}
#[doc = " Represents a struct declaration."]
#[doc = ""]
#[doc = " <div rustbindgen derive=\"Clone\" derive=\"Debug\"></div>"]
#[repr(C)]
#[derive(Clone, Debug)]
pub struct StructInfo {
#[doc = " Struct name"]
pub name: *const ::std::os::raw::c_char,
#[doc = " Struct fields' information"]
pub field_types: *const TypeInfo,
#[doc = " Number of fields"]
pub num_fields: u16,
}
#[test]
fn bindgen_test_layout_StructInfo() {
assert_eq!(
::std::mem::size_of::<StructInfo>(),
24usize,
concat!("Size of: ", stringify!(StructInfo))
);
assert_eq!(
::std::mem::align_of::<StructInfo>(),
8usize,
concat!("Alignment of ", stringify!(StructInfo))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).name as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(name)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).field_types as *const _ as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(field_types)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).num_fields as *const _ as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(num_fields)
)
);
}
#[doc = " Represents a module declaration."]
#[doc = ""]
#[doc = " <div rustbindgen derive=\"Debug\"></div>"]
Expand All @@ -218,12 +274,16 @@ 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,
}
#[test]
fn bindgen_test_layout_ModuleInfo() {
assert_eq!(
::std::mem::size_of::<ModuleInfo>(),
24usize,
40usize,
concat!("Size of: ", stringify!(ModuleInfo))
);
assert_eq!(
Expand Down Expand Up @@ -261,6 +321,26 @@ fn bindgen_test_layout_ModuleInfo() {
stringify!(num_functions)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).structs as *const _ as usize },
24usize,
concat!(
"Offset of field: ",
stringify!(ModuleInfo),
"::",
stringify!(structs)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).num_structs as *const _ as usize },
32usize,
concat!(
"Offset of field: ",
stringify!(ModuleInfo),
"::",
stringify!(num_structs)
)
);
}
#[doc = " Represents a function dispatch table. This is used for runtime linking."]
#[doc = ""]
Expand Down Expand Up @@ -339,7 +419,7 @@ pub struct AssemblyInfo {
fn bindgen_test_layout_AssemblyInfo() {
assert_eq!(
::std::mem::size_of::<AssemblyInfo>(),
64usize,
80usize,
concat!("Size of: ", stringify!(AssemblyInfo))
);
assert_eq!(
Expand All @@ -359,7 +439,7 @@ fn bindgen_test_layout_AssemblyInfo() {
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<AssemblyInfo>())).dispatch_table as *const _ as usize },
24usize,
40usize,
concat!(
"Offset of field: ",
stringify!(AssemblyInfo),
Expand All @@ -369,7 +449,7 @@ fn bindgen_test_layout_AssemblyInfo() {
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<AssemblyInfo>())).dependencies as *const _ as usize },
48usize,
64usize,
concat!(
"Offset of field: ",
stringify!(AssemblyInfo),
Expand All @@ -379,7 +459,7 @@ fn bindgen_test_layout_AssemblyInfo() {
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<AssemblyInfo>())).num_dependencies as *const _ as usize },
56usize,
72usize,
concat!(
"Offset of field: ",
stringify!(AssemblyInfo),
Expand Down
115 changes: 100 additions & 15 deletions crates/mun_abi/src/autogen_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@ unsafe impl Sync for FunctionSignature {}
unsafe impl Send for FunctionInfo {}
unsafe impl Sync for FunctionInfo {}

impl StructInfo {
/// Returns the struct's name.
pub fn name(&self) -> &str {
unsafe { CStr::from_ptr(self.name) }
.to_str()
.expect("Function name contains invalid UTF8")
}

/// Returns the struct's fields' types.
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) }
}
}
}

impl ModuleInfo {
/// Returns the module's full path.
pub fn path(&self) -> &str {
Expand Down Expand Up @@ -82,6 +100,15 @@ impl ModuleInfo {
unsafe { slice::from_raw_parts(self.functions, self.num_functions as usize) }
}
}

/// Returns the module's structs.
pub fn structs(&self) -> &[StructInfo] {
if self.num_structs == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.structs, self.num_structs as usize) }
}
}
}

unsafe impl Send for ModuleInfo {}
Expand Down Expand Up @@ -202,7 +229,7 @@ mod tests {
b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
};

const FAKE_TYPE_NAME: &'static str = "type-name";
const FAKE_TYPE_NAME: &str = "type-name";

#[test]
fn test_type_info_name() {
Expand Down Expand Up @@ -235,7 +262,7 @@ mod tests {
}
}

const FAKE_FN_NAME: &'static str = "fn-name";
const FAKE_FN_NAME: &str = "fn-name";

#[test]
fn test_fn_signature_name() {
Expand Down Expand Up @@ -296,35 +323,82 @@ mod tests {
assert_eq!(fn_signature.return_type(), return_type);
}

fn fake_module_info(path: &CStr, functions: &[FunctionInfo]) -> ModuleInfo {
fn fake_struct_info(name: &CStr, field_types: &[TypeInfo]) -> StructInfo {
StructInfo {
name: name.as_ptr(),
field_types: field_types.as_ptr(),
num_fields: field_types.len() as u16,
}
}

const FAKE_STRUCT_NAME: &str = "struct-name";

#[test]
fn test_struct_info_name() {
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_info = fake_struct_info(&struct_name, &[]);

assert_eq!(struct_info.name(), FAKE_STRUCT_NAME);
}

#[test]
fn test_struct_info_field_types_none() {
let field_types = &[];
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_info = fake_struct_info(&struct_name, field_types);

assert_eq!(struct_info.field_types(), field_types);
}

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

let field_types = &[type_info];
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_info = fake_struct_info(&struct_name, field_types);

assert_eq!(struct_info.field_types(), field_types);
}

fn fake_module_info(
path: &CStr,
functions: &[FunctionInfo],
structs: &[StructInfo],
) -> 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,
}
}

const FAKE_MODULE_PATH: &'static str = "path::to::module";
const FAKE_MODULE_PATH: &str = "path::to::module";

#[test]
fn test_module_info_path() {
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, &[]);
let module = fake_module_info(&module_path, &[], &[]);

assert_eq!(module.path(), FAKE_MODULE_PATH);
}

#[test]
fn test_module_info_functions_none() {
fn test_module_info_types_none() {
let functions = &[];
let structs = &[];
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, functions);
let module = fake_module_info(&module_path, functions, structs);

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

#[test]
fn test_module_info_functions_some() {
fn test_module_info_types_some() {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
let type_info = fake_type_info(&type_name);

Expand All @@ -336,20 +410,31 @@ mod tests {
signature: fn_signature,
fn_ptr: ptr::null(),
};

let functions = &[fn_info];

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 module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, functions);
let module = fake_module_info(&module_path, functions, structs);

let result = module.functions();
assert_eq!(result.len(), functions.len());
for (lhs, rhs) in result.iter().zip(functions.iter()) {
let result_functions = module.functions();
assert_eq!(result_functions.len(), functions.len());
for (lhs, rhs) in result_functions.iter().zip(functions.iter()) {
assert_eq!(lhs.fn_ptr, rhs.fn_ptr);
assert_eq!(lhs.signature.name(), rhs.signature.name());
assert_eq!(lhs.signature.arg_types(), rhs.signature.arg_types());
assert_eq!(lhs.signature.return_type(), rhs.signature.return_type());
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()) {
assert_eq!(lhs.name(), rhs.name());
assert_eq!(lhs.field_types(), rhs.field_types());
}
}

fn fake_dispatch_table(
Expand Down Expand Up @@ -555,12 +640,12 @@ mod tests {
}
}

const FAKE_DEPENDENCY: &'static str = "path/to/dependency.dylib";
const FAKE_DEPENDENCY: &str = "path/to/dependency.dylib";

#[test]
fn test_assembly_info_dependencies() {
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, &[]);
let module = fake_module_info(&module_path, &[], &[]);

let dispatch_table = fake_dispatch_table(&[], &mut []);

Expand Down
2 changes: 1 addition & 1 deletion crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
description = "LLVM IR code generation for Mun"

[dependencies]
mun_hir = { path = "../mun_hir" }
hir = { path = "../mun_hir", package = "mun_hir" }
mun_target = { path = "../mun_target" }
mun_lld = { path = "../mun_lld" }
failure = "0.1.5"
Expand Down
3 changes: 2 additions & 1 deletion crates/mun_codegen/src/code_gen.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::code_gen::linker::LinkerError;
use crate::IrDatabase;
use failure::Fail;
use hir::FileId;
use inkwell::module::Module;
use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target};
use inkwell::OptimizationLevel;
use mun_hir::FileId;
use std::io::{self, Write};
use std::path::Path;

Expand Down Expand Up @@ -61,6 +61,7 @@ pub fn write_module_shared_object(
symbols::gen_reflection_ir(
db,
&module.functions,
&module.structs,
&module.dispatch_table,
&assembly_module,
);
Expand Down
Loading

0 comments on commit 267f3c3

Please sign in to comment.