Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(runtime): add marshalling of value structs #93

Merged
merged 6 commits into from
Mar 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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