Skip to content

Commit

Permalink
Merge pull request #93 from Wodann/feature/marshal-value-struct
Browse files Browse the repository at this point in the history
feat(runtime): add marshalling of value structs
  • Loading branch information
baszalmstra authored Mar 7, 2020
2 parents 8f4834e + 3a716ad commit 9db3a2f
Show file tree
Hide file tree
Showing 37 changed files with 841 additions and 355 deletions.
7 changes: 5 additions & 2 deletions crates/mun/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[macro_use]
extern crate failure;

use std::cell::RefCell;
use std::rc::Rc;
use std::time::Duration;

use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
Expand Down Expand Up @@ -84,10 +86,11 @@ fn build(matches: &ArgMatches) -> Result<(), failure::Error> {

/// Starts the runtime with the specified library and invokes function `entry`.
fn start(matches: &ArgMatches) -> Result<(), failure::Error> {
let mut runtime = runtime(matches)?;
let runtime = Rc::new(RefCell::new(runtime(matches)?));

let borrowed = runtime.borrow();
let entry_point = matches.value_of("entry").unwrap_or("main");
let fn_info = runtime.get_function_info(entry_point).ok_or_else(|| {
let fn_info = borrowed.get_function_info(entry_point).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Failed to obtain entry point '{}'", entry_point),
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_abi/c
Submodule c updated 1 files
+25 −0 include/mun_abi.h
14 changes: 13 additions & 1 deletion crates/mun_abi/src/autogen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* automatically generated by rust-bindgen */

#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
use crate::{Privacy, TypeGroup};
use crate::{Privacy, StructMemoryKind, TypeGroup};

#[doc = " Represents a globally unique identifier (GUID)."]
#[doc = ""]
Expand Down Expand Up @@ -236,6 +236,8 @@ pub struct StructInfo {
pub field_sizes: *const u16,
#[doc = " Number of fields"]
pub num_fields: u16,
#[doc = " Struct memory kind"]
pub memory_kind: StructMemoryKind,
}
#[test]
fn bindgen_test_layout_StructInfo() {
Expand Down Expand Up @@ -309,6 +311,16 @@ fn bindgen_test_layout_StructInfo() {
stringify!(num_fields)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).memory_kind as *const _ as usize },
42usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(memory_kind)
)
);
}
#[doc = " Represents a module declaration."]
#[doc = ""]
Expand Down
28 changes: 26 additions & 2 deletions crates/mun_abi/src/autogen_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ mod tests {
field_types: &[&TypeInfo],
field_offsets: &[u16],
field_sizes: &[u16],
memory_kind: StructMemoryKind,
) -> StructInfo {
assert!(field_names.len() == field_types.len());
assert!(field_types.len() == field_offsets.len());
Expand All @@ -480,6 +481,7 @@ mod tests {
field_offsets: field_offsets.as_ptr(),
field_sizes: field_sizes.as_ptr(),
num_fields: field_names.len() as u16,
memory_kind,
}
}

Expand All @@ -488,7 +490,7 @@ mod tests {
#[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, &[], &[], &[], &[]);
let struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[], Default::default());

assert_eq!(struct_info.name(), FAKE_STRUCT_NAME);
}
Expand All @@ -506,6 +508,7 @@ mod tests {
field_types,
field_offsets,
field_sizes,
Default::default(),
);

assert_eq!(struct_info.field_names().count(), 0);
Expand All @@ -531,6 +534,7 @@ mod tests {
field_types,
field_offsets,
field_sizes,
Default::default(),
);

for (lhs, rhs) in struct_info.field_names().zip([FAKE_FIELD_NAME].iter()) {
Expand All @@ -555,6 +559,26 @@ mod tests {
}
}

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

assert_eq!(struct_info.memory_kind, struct_memory_kind);
}

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

assert_eq!(struct_info.memory_kind, struct_memory_kind);
}

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

#[test]
Expand Down Expand Up @@ -592,7 +616,7 @@ mod tests {
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 struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[], Default::default());
let struct_type_info = fake_struct_type_info(&struct_name, struct_info);
let types = &[unsafe { mem::transmute(&struct_type_info) }];

Expand Down
32 changes: 31 additions & 1 deletion crates/mun_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,37 @@ pub use autogen::*;
/// The *prelude* contains imports that are used almost every time.
pub mod prelude {
pub use crate::autogen::*;
pub use crate::{Privacy, TypeGroup};
pub use crate::{Privacy, StructMemoryKind, TypeGroup};
}

/// Represents the kind of memory management a struct uses.
#[repr(u8)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StructMemoryKind {
/// A garbage collected struct is allocated on the heap and uses reference semantics when passed
/// around.
GC,

/// A value struct is allocated on the stack and uses value semantics when passed around.
///
/// NOTE: When a value struct is used in an external API, a wrapper is created that _pins_ the
/// value on the heap. The heap-allocated value needs to be *manually deallocated*!
Value,
}

impl Default for StructMemoryKind {
fn default() -> Self {
StructMemoryKind::GC
}
}

impl From<StructMemoryKind> for u64 {
fn from(kind: StructMemoryKind) -> Self {
match kind {
StructMemoryKind::GC => 0,
StructMemoryKind::Value => 1,
}
}
}

/// Represents the privacy level of modules, functions, or variables.
Expand Down
1 change: 1 addition & 0 deletions crates/mun_codegen/src/code_gen/abi_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub(super) fn gen_abi_types(context: ContextRef) -> AbiTypes {
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
context.i8_type().into(), // memory_kind
],
false,
);
Expand Down
14 changes: 9 additions & 5 deletions crates/mun_codegen/src/code_gen/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::ir::{
};
use crate::type_info::{TypeGroup, TypeInfo};
use crate::values::{BasicValue, GlobalValue};
use crate::IrDatabase;
use crate::{CodeGenParams, IrDatabase};
use hir::Ty;
use inkwell::{
attributes::Attribute,
Expand Down Expand Up @@ -262,7 +262,6 @@ fn gen_function_info_array<'a, D: IrDatabase>(
functions: impl Iterator<Item = (&'a hir::Function, &'a FunctionValue)>,
) -> GlobalArrayValue {
let function_infos: Vec<StructValue> = functions
.filter(|(f, _)| f.visibility(db) == hir::Visibility::Public)
.map(|(f, value)| {
// Get the function from the cloned module and modify the linkage of the function.
let value = module
Expand Down Expand Up @@ -321,9 +320,9 @@ fn gen_struct_info<D: IrDatabase>(
(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 = fields.iter().map(|field| {
target_data.get_store_size(&db.type_ir(field.ty(db), CodeGenParams { is_extern: false }))
});
let (field_sizes, _) = gen_u16_array(module, field_sizes);

types.struct_info_type.const_named_struct(&[
Expand All @@ -337,6 +336,11 @@ fn gen_struct_info<D: IrDatabase>(
.i16_type()
.const_int(num_fields as u64, false)
.into(),
module
.get_context()
.i8_type()
.const_int(s.data(db).memory_kind.clone().into(), false)
.into(),
])
}

Expand Down
6 changes: 3 additions & 3 deletions crates/mun_codegen/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::type_repetition_in_bounds)]

use crate::{ir::module::ModuleIR, type_info::TypeInfo, Context};
use crate::{ir::module::ModuleIR, type_info::TypeInfo, CodeGenParams, Context};
use inkwell::types::StructType;
use inkwell::{types::AnyTypeEnum, OptimizationLevel};
use mun_target::spec::Target;
Expand All @@ -22,9 +22,9 @@ pub trait IrDatabase: hir::HirDatabase {
#[salsa::input]
fn target(&self) -> Target;

/// Given a type, return the corresponding IR type.
/// Given a type and code generation parameters, return the corresponding IR type.
#[salsa::invoke(crate::ir::ty::ir_query)]
fn type_ir(&self, ty: hir::Ty) -> AnyTypeEnum;
fn type_ir(&self, ty: hir::Ty, params: CodeGenParams) -> AnyTypeEnum;

/// Given a struct, return the corresponding IR type.
#[salsa::invoke(crate::ir::ty::struct_ty_query)]
Expand Down
3 changes: 3 additions & 0 deletions crates/mun_codegen/src/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::ir::dispatch_table::FunctionPrototype;
use crate::type_info::TypeInfo;
use inkwell::context::Context;
use inkwell::types::FunctionType;

Expand All @@ -18,4 +19,6 @@ pub trait Intrinsic: Sync {
intrinsics! {
/// Allocates memory from the runtime to use in code.
pub fn malloc(size: u64, alignment: u64) -> *mut u8;
/// Allocates memory for and clones the specified type located at `src` into it.
pub fn clone(src: *const u8, ty: *const TypeInfo) -> *mut u8;
}
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/intrinsics/macros.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
macro_rules! intrinsics{
($($(#[$attr:meta])* pub fn $name:ident($($arg_name:ident:$arg:ty),*) -> $ret:ty;);*) => {
($($(#[$attr:meta])* pub fn $name:ident($($arg_name:ident:$arg:ty),+) -> $ret:ty;)+) => {
$(
paste::item! {
pub struct [<Intrinsic $name>];
Expand Down
8 changes: 8 additions & 0 deletions crates/mun_codegen/src/ir.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::type_info::TypeInfo;
use inkwell::context::Context;
use inkwell::types::{
AnyType, AnyTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, PointerType,
Expand Down Expand Up @@ -183,6 +184,13 @@ impl<S: BasicType, T: IsIrType<Type = S>> IsPointerType for *const T {
}
}

// HACK: Manually add `*const TypeInfo`
impl IsPointerType for *const TypeInfo {
fn ir_type(context: &Context) -> PointerType {
context.i8_type().ptr_type(AddressSpace::Const)
}
}

impl<S: BasicType, T: IsIrType<Type = S>> IsPointerType for *mut T {
fn ir_type(context: &Context) -> PointerType {
T::ir_type(context).ptr_type(AddressSpace::Generic)
Expand Down
4 changes: 2 additions & 2 deletions crates/mun_codegen/src/ir/adt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//use crate::ir::module::Types;
use crate::ir::try_convert_any_to_basic;
use crate::IrDatabase;
use crate::{CodeGenParams, IrDatabase};
use inkwell::types::{BasicTypeEnum, StructType};

pub(super) fn gen_struct_decl(db: &impl IrDatabase, s: hir::Struct) -> StructType {
Expand All @@ -11,7 +11,7 @@ pub(super) fn gen_struct_decl(db: &impl IrDatabase, s: hir::Struct) -> StructTyp
.iter()
.map(|field| {
let field_type = field.ty(db);
try_convert_any_to_basic(db.type_ir(field_type))
try_convert_any_to_basic(db.type_ir(field_type, CodeGenParams { is_extern: false }))
.expect("could not convert field type")
})
.collect();
Expand Down
Loading

0 comments on commit 9db3a2f

Please sign in to comment.