Changeset - 0385b9bf770e
[Not reviewed]
0 2 0
MH - 4 years ago 2021-12-14 22:57:29
contact@maxhenger.nl
Remove unused DefinitionId, and reduce util struct size, in TypeTable breadcrumbs
2 files changed with 284 insertions and 295 deletions:
0 comments (0 inline, 0 general)
src/protocol/parser/type_table.rs
Show inline comments
 
@@ -341,6 +341,7 @@ pub struct StructMonomorphField {
 
/// Union monomorph
 
pub struct UnionMonomorph {
 
    pub variants: Vec<UnionMonomorphVariant>,
 
    pub tag_size: usize, // copied from `UnionType` upon monomorph construction.
 
    // note that the stack size is in the `TypeMonomorph` struct. This size and
 
    // alignment will include the size of the union tag.
 
    //
 
@@ -397,7 +398,7 @@ pub struct TupleMonomorphMember {
 
/// polymorphic variable).
 
struct MonomorphKey {
 
    parts: Vec<ConcreteTypePart>,
 
    in_use: Vec<bool>,
 
    in_use: Vec<bool>, // TODO: @Performance, limit num args and use two `u64` as bitflags or something
 
}
 

	
 
use std::hash::*;
 
@@ -563,7 +564,6 @@ impl MonomorphTable {
 
// Programmer note: keep this struct free of dynamically allocated memory
 
#[derive(Clone)]
 
struct TypeLoopBreadcrumb {
 
    definition_id: DefinitionId, // TODO: Check if it can be removed?
 
    monomorph_idx: i32,
 
    next_member: u32,
 
    next_embedded: u32, // for unions, the index into the variant's embedded types
 
@@ -571,11 +571,10 @@ struct TypeLoopBreadcrumb {
 

	
 
#[derive(Clone)]
 
struct MemoryBreadcrumb {
 
    definition_id: DefinitionId,
 
    monomorph_idx: i32,
 
    next_member: usize,
 
    next_embedded: usize,
 
    first_size_alignment_idx: usize,
 
    next_member: u32,
 
    next_embedded: u32,
 
    first_size_alignment_idx: u32,
 
}
 

	
 
#[derive(Debug, PartialEq, Eq)]
 
@@ -592,7 +591,6 @@ enum MemoryLayoutResult {
 

	
 
// TODO: @Optimize, initial memory-unoptimized implementation
 
struct TypeLoopEntry {
 
    definition_id: DefinitionId,
 
    monomorph_idx: i32,
 
    is_union: bool,
 
}
 
@@ -712,6 +710,7 @@ impl TypeTable {
 

	
 
    /// Returns the index into the monomorph type array if the procedure type
 
    /// already has a (reserved) monomorph.
 
    /// FIXME: This really shouldn't be called from within the runtime. See UnsafeCell in MonomorphTable
 
    #[inline]
 
    pub(crate) fn get_procedure_monomorph_index(&self, definition_id: &DefinitionId, type_parts: &[ConcreteTypePart]) -> Option<i32> {
 
        let base_type = self.type_lookup.get(definition_id).unwrap();
 
@@ -774,7 +773,6 @@ impl TypeTable {
 
        // Doesn't exist, so instantiate a monomorph and determine its memory
 
        // layout.
 
        self.detect_and_resolve_type_loops_for(modules, heap, concrete_type)?;
 
        debug_assert_eq!(self.encountered_types[0].definition_id, definition_id);
 
        let mono_idx = self.encountered_types[0].monomorph_idx;
 
        self.lay_out_memory_for_encountered_types(arch);
 

	
 
@@ -1043,7 +1041,7 @@ impl TypeTable {
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of component
 
        // FIXME: Marking used polymorphic variables on procedures requires
 
        // TODO: Marking used polymorphic variables on procedures requires
 
        //  making sure that each is used in the body. For now, mark them all
 
        //  as required.
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 
@@ -1209,8 +1207,6 @@ impl TypeTable {
 
        // we throw an error). If there are no type loops or they are all
 
        // resolvable then we end up with a list of `encountered_types`. These
 
        // are then used by `lay_out_memory_for_encountered_types`.
 
        use DefinedTypeVariant as DTV;
 

	
 
        debug_assert!(self.type_loop_breadcrumbs.is_empty());
 
        debug_assert!(self.type_loops.is_empty());
 
        debug_assert!(self.encountered_types.is_empty());
 
@@ -1229,82 +1225,74 @@ impl TypeTable {
 
            let breadcrumb_idx = self.type_loop_breadcrumbs.len() - 1;
 
            let mut breadcrumb = self.type_loop_breadcrumbs[breadcrumb_idx].clone();
 

	
 
            // TODO: Also don't need DefinitionId here. So then only need mono_index, so then just
 
            //  do a switch on the monomorph, not on the base type.
 
            let resolve_result = if breadcrumb.definition_id.is_invalid() {
 
                // We're dealing with a tuple
 
                let monomorph = self.mono_lookup.get(breadcrumb.monomorph_idx).variant.as_tuple();
 
                let num_members = monomorph.members.len() as u32;
 
                let mut tuple_result = TypeLoopResult::TypeExists;
 
            let monomorph = self.mono_lookup.get(breadcrumb.monomorph_idx);
 
            let resolve_result = match &monomorph.variant {
 
                MonomorphVariant::Enum => {
 
                    TypeLoopResult::TypeExists
 
                },
 
                MonomorphVariant::Union(monomorph) => {
 
                    let num_variants = monomorph.variants.len() as u32;
 
                    let mut union_result = TypeLoopResult::TypeExists;
 

	
 
                    'member_loop: while breadcrumb.next_member < num_variants {
 
                        let mono_variant = &monomorph.variants[breadcrumb.next_member as usize];
 
                        let num_embedded = mono_variant.embedded.len() as u32;
 

	
 
                        while breadcrumb.next_embedded < num_embedded {
 
                            let mono_embedded = &mono_variant.embedded[breadcrumb.next_embedded as usize];
 
                            union_result = self.check_member_for_type_loops(&mono_embedded.concrete_type);
 

	
 
                            if union_result != TypeLoopResult::TypeExists {
 
                                // In type loop or new breadcrumb pushed, so
 
                                // break out of the resolving loop
 
                                break 'member_loop;
 
                            }
 

	
 
                while breadcrumb.next_member < num_members {
 
                    let tuple_member = &monomorph.members[breadcrumb.next_member as usize];
 
                    tuple_result = self.check_member_for_type_loops(&tuple_member.concrete_type);
 
                            breadcrumb.next_embedded += 1;
 
                        }
 

	
 
                    if tuple_result != TypeLoopResult::TypeExists {
 
                        break;
 
                        breadcrumb.next_embedded = 0;
 
                        breadcrumb.next_member += 1
 
                    }
 

	
 
                    breadcrumb.next_member += 1;
 
                }
 

	
 
                tuple_result
 
            } else {
 
                let poly_type = self.type_lookup.get(&breadcrumb.definition_id).unwrap();
 
                match &poly_type.definition {
 
                    DTV::Enum(_) => {
 
                        TypeLoopResult::TypeExists
 
                    },
 
                    DTV::Union(definition) => {
 
                        let monomorph = self.mono_lookup.get(breadcrumb.monomorph_idx).variant.as_union();
 
                        let num_variants = monomorph.variants.len() as u32;
 

	
 
                        let mut union_result = TypeLoopResult::TypeExists;
 

	
 
                        'member_loop: while breadcrumb.next_member < num_variants {
 
                            let mono_variant = &monomorph.variants[breadcrumb.next_member as usize];
 
                            let num_embedded = mono_variant.embedded.len() as u32;
 
                    union_result
 
                },
 
                MonomorphVariant::Struct(monomorph) => {
 
                    let num_fields = monomorph.fields.len() as u32;
 

	
 
                    let mut struct_result = TypeLoopResult::TypeExists;
 
                    while breadcrumb.next_member < num_fields {
 
                        let mono_field = &monomorph.fields[breadcrumb.next_member as usize];
 
                        struct_result = self.check_member_for_type_loops(&mono_field.concrete_type);
 

	
 
                        if struct_result != TypeLoopResult::TypeExists {
 
                            // Type loop or breadcrumb pushed, so break out of
 
                            // the resolving loop
 
                            break;
 
                        }
 

	
 
                            while breadcrumb.next_embedded < num_embedded {
 
                                let mono_embedded = &mono_variant.embedded[breadcrumb.next_embedded as usize];
 
                                union_result = self.check_member_for_type_loops(&mono_embedded.concrete_type);
 
                        breadcrumb.next_member += 1;
 
                    }
 

	
 
                                if union_result != TypeLoopResult::TypeExists {
 
                                    // In type loop or new breadcrumb pushed, so
 
                                    // break out of the resolving loop
 
                                    break 'member_loop;
 
                                }
 
                    struct_result
 
                },
 
                MonomorphVariant::Procedure(_) => unreachable!(),
 
                MonomorphVariant::Tuple(monomorph) => {
 
                    let num_members = monomorph.members.len() as u32;
 
                    let mut tuple_result = TypeLoopResult::TypeExists;
 

	
 
                                breadcrumb.next_embedded += 1;
 
                            }
 
                    while breadcrumb.next_member < num_members {
 
                        let tuple_member = &monomorph.members[breadcrumb.next_member as usize];
 
                        tuple_result = self.check_member_for_type_loops(&tuple_member.concrete_type);
 

	
 
                            breadcrumb.next_embedded = 0;
 
                            breadcrumb.next_member += 1
 
                        if tuple_result != TypeLoopResult::TypeExists {
 
                            break;
 
                        }
 

	
 
                        union_result
 
                    },
 
                    DTV::Struct(definition) => {
 
                        let monomorph = self.mono_lookup.get(breadcrumb.monomorph_idx).variant.as_struct();
 
                        let num_fields = monomorph.fields.len() as u32;
 

	
 
                        let mut struct_result = TypeLoopResult::TypeExists;
 
                        while breadcrumb.next_member < num_fields {
 
                            let mono_field = &monomorph.fields[breadcrumb.next_member as usize];
 
                            struct_result = self.check_member_for_type_loops(&mono_field.concrete_type);
 

	
 
                            if struct_result != TypeLoopResult::TypeExists {
 
                                // Type loop or breadcrumb pushed, so break out of
 
                                // the resolving loop
 
                                break;
 
                            }
 

	
 
                            breadcrumb.next_member += 1;
 
                        }
 
                        breadcrumb.next_member += 1;
 
                    }
 

	
 
                        struct_result
 
                    },
 
                    DTV::Function(_) | DTV::Component(_) => unreachable!(),
 
                    tuple_result
 
                }
 
            };
 

	
 
@@ -1332,14 +1320,13 @@ impl TypeTable {
 
                        let breadcrumb = &mut self.type_loop_breadcrumbs[breadcrumb_idx];
 
                        let mut is_union = false;
 

	
 
                        let entry = self.type_lookup.get_mut(&breadcrumb.definition_id).unwrap();
 
                        let monomorph = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                        // TODO: Match on monomorph directly here
 
                        match &mut entry.definition {
 
                            DTV::Union(definition) => {
 
                        match &mut monomorph.variant {
 
                            MonomorphVariant::Union(monomorph) => {
 
                                // Mark the currently processed variant as requiring heap
 
                                // allocation, then advance the *embedded* type. The loop above
 
                                // will then take care of advancing it to the next *member*.
 
                                let monomorph = self.mono_lookup.get_mut(breadcrumb.monomorph_idx).variant.as_union_mut();
 
                                let variant = &mut monomorph.variants[breadcrumb.next_member as usize];
 
                                variant.lives_on_heap = true;
 
                                breadcrumb.next_embedded += 1;
 
@@ -1350,7 +1337,6 @@ impl TypeTable {
 
                        }
 

	
 
                        loop_members.push(TypeLoopEntry{
 
                            definition_id: breadcrumb.definition_id,
 
                            monomorph_idx: breadcrumb.monomorph_idx,
 
                            is_union
 
                        });
 
@@ -1381,20 +1367,14 @@ impl TypeTable {
 
        // a type loop.
 
        fn type_loop_source_span_and_message<'a>(
 
            modules: &'a [Module], heap: &Heap, mono_lookup: &MonomorphTable,
 
            defined_type: &DefinedType, monomorph_idx: i32, index_in_loop: usize
 
            definition_id: DefinitionId, monomorph_idx: i32, index_in_loop: usize
 
        ) -> (&'a InputSource, InputSpan, String) {
 
            // Note: because we will discover the type loop the *first* time we
 
            // instantiate a monomorph with the provided polymorphic arguments
 
            // (not all arguments are actually used in the type). We don't have
 
            // to care about a second instantiation where certain unused
 
            // polymorphic arguments are different.
 
            // TODO: Also remove match on defined_type, replace with mono lookup
 
            let monomorph_type = match &defined_type.definition {
 
                DTV::Union(definition) => &mono_lookup.get(monomorph_idx).concrete_type,
 
                DTV::Struct(definition) => &mono_lookup.get(monomorph_idx).concrete_type,
 
                DTV::Enum(_) | DTV::Function(_) | DTV::Component(_) =>
 
                    unreachable!(), // impossible to have an enum/procedure in a type loop
 
            };
 
            let monomorph_type = &mono_lookup.get(monomorph_idx).concrete_type;
 

	
 
            let type_name = monomorph_type.display_name(&heap);
 
            let message = if index_in_loop == 0 {
 
@@ -1410,7 +1390,7 @@ impl TypeTable {
 
                format!("which depends on the type '{}'", type_name)
 
            };
 

	
 
            let ast_definition = &heap[defined_type.ast_definition];
 
            let ast_definition = &heap[definition_id];
 
            let ast_root_id = ast_definition.defined_in();
 

	
 
            return (
 
@@ -1420,25 +1400,48 @@ impl TypeTable {
 
            );
 
        }
 

	
 
        fn retrieve_definition_id_if_possible(parts: &[ConcreteTypePart]) -> DefinitionId {
 
            match &parts[0] {
 
                ConcreteTypePart::Instance(v, _) |
 
                ConcreteTypePart::Function(v, _) |
 
                ConcreteTypePart::Component(v, _) => *v,
 
                _ => DefinitionId::new_invalid(),
 
            }
 
        }
 

	
 
        fn construct_type_loop_error(table: &TypeTable, type_loop: &TypeLoop, modules: &[Module], heap: &Heap) -> ParseError {
 
            let first_entry = &type_loop.members[0];
 
            let first_type = table.type_lookup.get(&first_entry.definition_id).unwrap();
 
            let (first_module, first_span, first_message) = type_loop_source_span_and_message(
 
                modules, heap, &table.mono_lookup, first_type, first_entry.monomorph_idx, 0
 
            );
 
            let mut parse_error = ParseError::new_error_at_span(first_module, first_span, first_message);
 
            // Seek first entry to produce parse error. Then continue builder
 
            // pattern. This is the error case so efficiency can go home.
 
            let mut parse_error = None;
 
            let mut next_member_index = 0;
 
            while next_member_index < type_loop.members.len() {
 
                let first_entry = &type_loop.members[next_member_index];
 
                next_member_index += 1;
 

	
 
                let first_definition_id = retrieve_definition_id_if_possible(&table.mono_lookup.get(first_entry.monomorph_idx).concrete_type.parts);
 
                if first_definition_id.is_invalid() {
 
                    continue;
 
                }
 

	
 
                let (first_module, first_span, first_message) = type_loop_source_span_and_message(
 
                    modules, heap, &table.mono_lookup, first_definition_id, first_entry.monomorph_idx, 0
 
                );
 
                parse_error = Some(ParseError::new_error_at_span(first_module, first_span, first_message));
 
                break;
 
            }
 

	
 
            let mut parse_error = parse_error.unwrap(); // Loop above cannot have failed, because we must have a type loop, type loops cannot contain only unnamed types
 

	
 
            let mut error_counter = 1;
 
            for member_idx in 1..type_loop.members.len() {
 
            for member_idx in next_member_index..type_loop.members.len() {
 
                let entry = &type_loop.members[member_idx];
 
                if entry.definition_id.is_invalid() {
 
                    // Don't display the tuples
 
                    continue;
 
                let definition_id = retrieve_definition_id_if_possible(&table.mono_lookup.get(entry.monomorph_idx).concrete_type.parts);
 
                if definition_id.is_invalid() {
 
                    continue; // dont display tuples
 
                }
 

	
 
                let entry_type = table.type_lookup.get(&first_entry.definition_id).unwrap();
 
                let (module, span, message) = type_loop_source_span_and_message(
 
                    modules, heap, &table.mono_lookup, entry_type, entry.monomorph_idx, error_counter
 
                    modules, heap, &table.mono_lookup, definition_id, entry.monomorph_idx, error_counter
 
                );
 
                parse_error = parse_error.with_info_at_span(module, span, message);
 
                error_counter += 1;
 
@@ -1453,7 +1456,7 @@ impl TypeTable {
 

	
 
            for entry in &type_loop.members {
 
                if entry.is_union {
 
                    let monomorph = &self.mono_lookup.get(entry.monomorph_idx).variant.as_union();
 
                    let monomorph = self.mono_lookup.get(entry.monomorph_idx).variant.as_union();
 
                    debug_assert!(!monomorph.variants.is_empty()); // otherwise it couldn't be part of the type loop
 
                    let has_stack_variant = monomorph.variants.iter().any(|variant| !variant.lives_on_heap);
 
                    if has_stack_variant {
 
@@ -1544,24 +1547,30 @@ impl TypeTable {
 
                        offset: 0
 
                    });
 
                }
 
                let monomorph_index = self.mono_lookup.insert_with_zero_size_and_alignment(
 
                let mono_index = self.mono_lookup.insert_with_zero_size_and_alignment(
 
                    definition_type, &[],
 
                    MonomorphVariant::Tuple(TupleMonomorph{
 
                        members,
 
                    })
 
                );
 

	
 
                monomorph_index
 
                mono_index
 
            },
 
            CTP::Instance(_check_definition_id, _) => {
 
                debug_assert_eq!(definition_id, *_check_definition_id); // because this is how `definition_id` was determined
 
                let base_type = self.type_lookup.get_mut(&definition_id).unwrap();
 
                let monomorph_index = match &mut base_type.definition {
 
                    DTV::Enum(definition) => {
 
                        // TODO: Is this correct?
 
                        // The enum is a bit exceptional in that when we insert
 
                        // it we we will immediately set its size/alignment:
 
                        // there is nothing to compute here.
 
                        debug_assert!(definition.size != 0 && definition.alignment != 0);
 
                        let mono_index = self.mono_lookup.insert_with_zero_size_and_alignment(
 
                            definition_type, &base_type.poly_vars, MonomorphVariant::Enum
 
                        );
 
                        let mono_type = self.mono_lookup.get_mut(mono_index);
 
                        mono_type.size = definition.size;
 
                        mono_type.alignment = definition.alignment;
 

	
 
                        mono_index
 
                    },
 
@@ -1590,6 +1599,7 @@ impl TypeTable {
 
                            definition_type, &base_type.poly_vars,
 
                            MonomorphVariant::Union(UnionMonomorph{
 
                                variants: mono_variants,
 
                                tag_size: definition.tag_size,
 
                                heap_size: 0,
 
                                heap_alignment: 0
 
                            })
 
@@ -1628,13 +1638,11 @@ impl TypeTable {
 
        };
 

	
 
        self.encountered_types.push(TypeLoopEntry{
 
            definition_id,
 
            monomorph_idx: monomorph_index,
 
            is_union,
 
        });
 

	
 
        self.type_loop_breadcrumbs.push(TypeLoopBreadcrumb{
 
            definition_id,
 
            monomorph_idx: monomorph_index,
 
            next_member: 0,
 
            next_embedded: 0,
 
@@ -1721,7 +1729,6 @@ impl TypeTable {
 
        // to store intermediate size/alignment pairs until all members are
 
        // resolved. Note that this `size_alignment_stack` is NOT an
 
        // optimization, we're working around borrowing rules here.
 
        use DefinedTypeVariant as DTV;
 

	
 
        // Just finished type loop detection, so we're left with the encountered
 
        // types only
 
@@ -1734,7 +1741,6 @@ impl TypeTable {
 
        // were detecting type loops)
 
        let first_entry = &self.encountered_types[0];
 
        self.memory_layout_breadcrumbs.push(MemoryBreadcrumb{
 
            definition_id: first_entry.definition_id,
 
            monomorph_idx: first_entry.monomorph_idx,
 
            next_member: 0,
 
            next_embedded: 0,
 
@@ -1746,199 +1752,190 @@ impl TypeTable {
 
            let cur_breadcrumb_idx = self.memory_layout_breadcrumbs.len() - 1;
 
            let mut breadcrumb = self.memory_layout_breadcrumbs[cur_breadcrumb_idx].clone();
 

	
 
            // TODO: Same as above, replace lookup of base definition, should not
 
            //  be needed.
 
            if breadcrumb.definition_id.is_invalid() {
 
                // Handle tuple
 
                let mono_tuple = self.mono_lookup.get(breadcrumb.monomorph_idx).variant.as_tuple();
 
                let num_members = mono_tuple.members.len();
 
                while breadcrumb.next_member < num_members {
 
                    let mono_member = &mono_tuple.members[breadcrumb.next_member];
 
                    match self.get_memory_layout_or_breadcrumb(arch, &mono_member.concrete_type.parts) {
 
                        MemoryLayoutResult::TypeExists(size, alignment) => {
 
                            self.size_alignment_stack.push((size, alignment));
 
                        },
 
                        MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                            self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                            self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                            continue 'breadcrumb_loop;
 
                        },
 
            let mono_type = self.mono_lookup.get(breadcrumb.monomorph_idx);
 
            match &mono_type.variant {
 
                MonomorphVariant::Enum => {
 
                    // Size should already be computed
 
                    if cfg!(debug_assertions) {
 
                        let mono_type = self.mono_lookup.get(breadcrumb.monomorph_idx);
 
                        debug_assert!(mono_type.size != 0 && mono_type.alignment != 0);
 
                    }
 

	
 
                    breadcrumb.next_member += 1;
 
                }
 

	
 
                // If here then we can compute the memory layout of the tuple.
 
                let mut cur_offset = 0;
 
                let mut max_alignment = 1;
 

	
 
                let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                let mono_tuple = mono_info.variant.as_tuple_mut();
 
                let mut size_alignment_index = breadcrumb.first_size_alignment_idx;
 
                for member_index in 0..num_members {
 
                    let (member_size, member_alignment) = self.size_alignment_stack[size_alignment_index];
 
                    align_offset_to(&mut cur_offset, member_alignment);
 
                    size_alignment_index += 1;
 

	
 
                    let member = &mut mono_tuple.members[member_index];
 
                    member.size = member_size;
 
                    member.alignment = member_alignment;
 
                    member.offset = cur_offset;
 

	
 
                    cur_offset += member_size;
 
                    max_alignment = max_alignment.max(member_alignment);
 
                }
 

	
 
                mono_info.size = cur_offset;
 
                mono_info.alignment = max_alignment;
 
                self.size_alignment_stack.truncate(breadcrumb.first_size_alignment_idx);
 
            } else {
 
                let poly_type = self.type_lookup.get(&breadcrumb.definition_id).unwrap();
 
                match &poly_type.definition {
 
                    DTV::Enum(definition) => {
 
                        // Size should already be computed
 
                        debug_assert!(definition.size != 0 && definition.alignment != 0);
 
                        let mono_type = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                        mono_type.size = definition.size;
 
                        mono_type.alignment = definition.alignment;
 
                    },
 
                    DTV::Union(definition) => {
 
                        // Retrieve size/alignment of each embedded type. We do not
 
                        // compute the offsets or total type sizes yet.
 
                        let mono_type = self.mono_lookup.get(breadcrumb.monomorph_idx).variant.as_union();
 
                        let num_variants = mono_type.variants.len();
 
                        while breadcrumb.next_member < num_variants {
 
                            let mono_variant = &mono_type.variants[breadcrumb.next_member];
 

	
 
                            if mono_variant.lives_on_heap {
 
                                // To prevent type loops we made this a heap-
 
                                // allocated variant. This implies we cannot
 
                                // compute sizes of members at this point.
 
                            } else {
 
                                let num_embedded = mono_variant.embedded.len();
 
                                while breadcrumb.next_embedded < num_embedded {
 
                                    let mono_embedded = &mono_variant.embedded[breadcrumb.next_embedded];
 
                                    match self.get_memory_layout_or_breadcrumb(arch, &mono_embedded.concrete_type.parts) {
 
                                        MemoryLayoutResult::TypeExists(size, alignment) => {
 
                                            self.size_alignment_stack.push((size, alignment));
 
                                        },
 
                                        MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                                            self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                                            self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                                            continue 'breadcrumb_loop;
 
                                        }
 
                },
 
                MonomorphVariant::Union(mono_type) => {
 
                    // Retrieve size/alignment of each embedded type. We do not
 
                    // compute the offsets or total type sizes yet.
 
                    let num_variants = mono_type.variants.len() as u32;
 
                    while breadcrumb.next_member < num_variants {
 
                        let mono_variant = &mono_type.variants[breadcrumb.next_member as usize];
 

	
 
                        if mono_variant.lives_on_heap {
 
                            // To prevent type loops we made this a heap-
 
                            // allocated variant. This implies we cannot
 
                            // compute sizes of members at this point.
 
                        } else {
 
                            let num_embedded = mono_variant.embedded.len() as u32;
 
                            while breadcrumb.next_embedded < num_embedded {
 
                                let mono_embedded = &mono_variant.embedded[breadcrumb.next_embedded as usize];
 
                                match self.get_memory_layout_or_breadcrumb(arch, &mono_embedded.concrete_type.parts) {
 
                                    MemoryLayoutResult::TypeExists(size, alignment) => {
 
                                        self.size_alignment_stack.push((size, alignment));
 
                                    },
 
                                    MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                                        self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                                        self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                                        continue 'breadcrumb_loop;
 
                                    }
 

	
 
                                    breadcrumb.next_embedded += 1;
 
                                }
 
                            }
 

	
 
                            breadcrumb.next_member += 1;
 
                            breadcrumb.next_embedded = 0;
 
                                breadcrumb.next_embedded += 1;
 
                            }
 
                        }
 

	
 
                        // If here then we can at least compute the stack size of
 
                        // the type, we'll have to come back at the very end to
 
                        // fill in the heap size/alignment/offset of each heap-
 
                        // allocated variant.
 
                        let mut max_size = definition.tag_size;
 
                        let mut max_alignment = definition.tag_size;
 

	
 
                        let poly_type = self.type_lookup.get_mut(&breadcrumb.definition_id).unwrap();
 
                        let definition = poly_type.definition.as_union_mut();
 
                        let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                        let mono_type = mono_info.variant.as_union_mut();
 
                        let mut size_alignment_idx = breadcrumb.first_size_alignment_idx;
 

	
 
                        for variant in &mut mono_type.variants {
 
                            // We're doing stack computations, so always start with
 
                            // the tag size/alignment.
 
                            let mut variant_offset = definition.tag_size;
 
                            let mut variant_alignment = definition.tag_size;
 

	
 
                            if variant.lives_on_heap {
 
                                // Variant lives on heap, so just a pointer
 
                                let (ptr_size, ptr_align) = arch.pointer_size_alignment;
 
                                align_offset_to(&mut variant_offset, ptr_align);
 

	
 
                                variant_offset += ptr_size;
 
                                variant_alignment = variant_alignment.max(ptr_align);
 
                            } else {
 
                                // Variant lives on stack, so walk all embedded
 
                                // types.
 
                                for embedded in &mut variant.embedded {
 
                                    let (size, alignment) = self.size_alignment_stack[size_alignment_idx];
 
                                    embedded.size = size;
 
                                    embedded.alignment = alignment;
 
                                    size_alignment_idx += 1;
 

	
 
                                    align_offset_to(&mut variant_offset, alignment);
 
                                    embedded.offset = variant_offset;
 

	
 
                                    variant_offset += size;
 
                                    variant_alignment = variant_alignment.max(alignment);
 
                                }
 
                            };
 

	
 
                            max_size = max_size.max(variant_offset);
 
                            max_alignment = max_alignment.max(variant_alignment);
 
                        }
 
                        breadcrumb.next_member += 1;
 
                        breadcrumb.next_embedded = 0;
 
                    }
 

	
 
                        mono_info.size = max_size;
 
                        mono_info.alignment = max_alignment;
 
                        self.size_alignment_stack.truncate(breadcrumb.first_size_alignment_idx);
 
                    },
 
                    DTV::Struct(definition) => {
 
                        // Retrieve size and alignment of each struct member. We'll
 
                        // compute the offsets once all of those are known
 
                        let mono_type = self.mono_lookup.get(breadcrumb.monomorph_idx).variant.as_struct();
 
                        let num_fields = mono_type.fields.len();
 
                        while breadcrumb.next_member < num_fields {
 
                            let mono_field = &mono_type.fields[breadcrumb.next_member];
 

	
 
                            match self.get_memory_layout_or_breadcrumb(arch, &mono_field.concrete_type.parts) {
 
                                MemoryLayoutResult::TypeExists(size, alignment) => {
 
                                    self.size_alignment_stack.push((size, alignment))
 
                                },
 
                                MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                                    self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                                    self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                                    continue 'breadcrumb_loop;
 
                                },
 
                    // If here then we can at least compute the stack size of
 
                    // the type, we'll have to come back at the very end to
 
                    // fill in the heap size/alignment/offset of each heap-
 
                    // allocated variant.
 
                    let mut max_size = mono_type.tag_size;
 
                    let mut max_alignment = mono_type.tag_size;
 

	
 
                    let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                    let mono_type = mono_info.variant.as_union_mut();
 
                    let mut size_alignment_idx = breadcrumb.first_size_alignment_idx as usize;
 

	
 
                    for variant in &mut mono_type.variants {
 
                        // We're doing stack computations, so always start with
 
                        // the tag size/alignment.
 
                        let mut variant_offset = mono_type.tag_size;
 
                        let mut variant_alignment = mono_type.tag_size;
 

	
 
                        if variant.lives_on_heap {
 
                            // Variant lives on heap, so just a pointer
 
                            let (ptr_size, ptr_align) = arch.pointer_size_alignment;
 
                            align_offset_to(&mut variant_offset, ptr_align);
 

	
 
                            variant_offset += ptr_size;
 
                            variant_alignment = variant_alignment.max(ptr_align);
 
                        } else {
 
                            // Variant lives on stack, so walk all embedded
 
                            // types.
 
                            for embedded in &mut variant.embedded {
 
                                let (size, alignment) = self.size_alignment_stack[size_alignment_idx];
 
                                embedded.size = size;
 
                                embedded.alignment = alignment;
 
                                size_alignment_idx += 1;
 

	
 
                                align_offset_to(&mut variant_offset, alignment);
 
                                embedded.offset = variant_offset;
 

	
 
                                variant_offset += size;
 
                                variant_alignment = variant_alignment.max(alignment);
 
                            }
 
                        };
 

	
 
                        max_size = max_size.max(variant_offset);
 
                        max_alignment = max_alignment.max(variant_alignment);
 
                    }
 

	
 
                            breadcrumb.next_member += 1;
 
                    mono_info.size = max_size;
 
                    mono_info.alignment = max_alignment;
 
                    self.size_alignment_stack.truncate(breadcrumb.first_size_alignment_idx as usize);
 
                },
 
                MonomorphVariant::Struct(mono_type) => {
 
                    // Retrieve size and alignment of each struct member. We'll
 
                    // compute the offsets once all of those are known
 
                    let num_fields = mono_type.fields.len() as u32;
 
                    while breadcrumb.next_member < num_fields {
 
                        let mono_field = &mono_type.fields[breadcrumb.next_member as usize];
 

	
 
                        match self.get_memory_layout_or_breadcrumb(arch, &mono_field.concrete_type.parts) {
 
                            MemoryLayoutResult::TypeExists(size, alignment) => {
 
                                self.size_alignment_stack.push((size, alignment))
 
                            },
 
                            MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                                self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                                self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                                continue 'breadcrumb_loop;
 
                            },
 
                        }
 

	
 
                        // Compute offsets and size of total type
 
                        let mut cur_offset = 0;
 
                        let mut max_alignment = 1;
 
                        breadcrumb.next_member += 1;
 
                    }
 

	
 
                    // Compute offsets and size of total type
 
                    let mut cur_offset = 0;
 
                    let mut max_alignment = 1;
 

	
 
                    let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                    let mono_type = mono_info.variant.as_struct_mut();
 
                    let mut size_alignment_idx = breadcrumb.first_size_alignment_idx as usize;
 

	
 
                        let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                        let mono_type = mono_info.variant.as_struct_mut();
 
                        let mut size_alignment_idx = breadcrumb.first_size_alignment_idx;
 
                    for field in &mut mono_type.fields {
 
                        let (size, alignment) = self.size_alignment_stack[size_alignment_idx];
 
                        field.size = size;
 
                        field.alignment = alignment;
 
                        size_alignment_idx += 1;
 

	
 
                        for field in &mut mono_type.fields {
 
                            let (size, alignment) = self.size_alignment_stack[size_alignment_idx];
 
                            field.size = size;
 
                            field.alignment = alignment;
 
                            size_alignment_idx += 1;
 
                        align_offset_to(&mut cur_offset, alignment);
 
                        field.offset = cur_offset;
 

	
 
                            align_offset_to(&mut cur_offset, alignment);
 
                            field.offset = cur_offset;
 
                        cur_offset += size;
 
                        max_alignment = max_alignment.max(alignment);
 
                    }
 

	
 
                            cur_offset += size;
 
                            max_alignment = max_alignment.max(alignment);
 
                    mono_info.size = cur_offset;
 
                    mono_info.alignment = max_alignment;
 
                    self.size_alignment_stack.truncate(breadcrumb.first_size_alignment_idx as usize);
 
                },
 
                MonomorphVariant::Procedure(_) => {
 
                    unreachable!();
 
                },
 
                MonomorphVariant::Tuple(mono_type) => {
 
                    let num_members = mono_type.members.len() as u32;
 
                    while breadcrumb.next_member < num_members {
 
                        let mono_member = &mono_type.members[breadcrumb.next_member as usize];
 
                        match self.get_memory_layout_or_breadcrumb(arch, &mono_member.concrete_type.parts) {
 
                            MemoryLayoutResult::TypeExists(size, alignment) => {
 
                                self.size_alignment_stack.push((size, alignment));
 
                            },
 
                            MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                                self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                                self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                                continue 'breadcrumb_loop;
 
                            },
 
                        }
 

	
 
                        mono_info.size = cur_offset;
 
                        mono_info.alignment = max_alignment;
 
                        self.size_alignment_stack.truncate(breadcrumb.first_size_alignment_idx);
 
                    },
 
                    DTV::Function(_) | DTV::Component(_) => {
 
                        unreachable!();
 
                        breadcrumb.next_member += 1;
 
                    }
 
                }
 

	
 
                    // If here then we can compute the memory layout of the tuple.
 
                    let mut cur_offset = 0;
 
                    let mut max_alignment = 1;
 

	
 
                    let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                    let mono_type = mono_info.variant.as_tuple_mut();
 
                    let mut size_alignment_index = breadcrumb.first_size_alignment_idx as usize;
 
                    for member_index in 0..num_members {
 
                        let (member_size, member_alignment) = self.size_alignment_stack[size_alignment_index];
 
                        align_offset_to(&mut cur_offset, member_alignment);
 
                        size_alignment_index += 1;
 

	
 
                        let member = &mut mono_type.members[member_index as usize];
 
                        member.size = member_size;
 
                        member.alignment = member_alignment;
 
                        member.offset = cur_offset;
 

	
 
                        cur_offset += member_size;
 
                        max_alignment = max_alignment.max(member_alignment);
 
                    }
 

	
 
                    mono_info.size = cur_offset;
 
                    mono_info.alignment = max_alignment;
 
                    self.size_alignment_stack.truncate(breadcrumb.first_size_alignment_idx as usize);
 
                },
 
            }
 

	
 
            // If here, then we completely layed out the current type. So move
 
@@ -2051,11 +2048,10 @@ impl TypeTable {
 
                    return MemoryLayoutResult::TypeExists(size, alignment);
 
                } else {
 
                    return MemoryLayoutResult::PushBreadcrumb(MemoryBreadcrumb{
 
                        definition_id: DefinitionId::new_invalid(),
 
                        monomorph_idx: mono_index,
 
                        next_member: 0,
 
                        next_embedded: 0,
 
                        first_size_alignment_idx: self.size_alignment_stack.len(),
 
                        first_size_alignment_idx: self.size_alignment_stack.len() as u32,
 
                    })
 
                }
 
            },
 
@@ -2069,11 +2065,10 @@ impl TypeTable {
 
                    return MemoryLayoutResult::TypeExists(size, alignment);
 
                } else {
 
                    return MemoryLayoutResult::PushBreadcrumb(MemoryBreadcrumb{
 
                        definition_id,
 
                        monomorph_idx: mono_index,
 
                        next_member: 0,
 
                        next_embedded: 0,
 
                        first_size_alignment_idx: self.size_alignment_stack.len(),
 
                        first_size_alignment_idx: self.size_alignment_stack.len() as u32,
 
                    });
 
                }
 
            },
src/protocol/tests/utils.rs
Show inline comments
 
@@ -924,8 +924,6 @@ impl<'a> ErrorTester<'a> {
 
//------------------------------------------------------------------------------
 

	
 
fn has_equal_num_monomorphs(ctx: TestCtx, num: usize, definition_id: DefinitionId) -> (bool, usize) {
 
    use DefinedTypeVariant::*;
 

	
 
    // Again: inefficient, but its testing code
 
    let type_def = ctx.types.get_base_definition(&definition_id).unwrap();
 
    let mut num_on_type = 0;
 
@@ -947,10 +945,6 @@ fn has_equal_num_monomorphs(ctx: TestCtx, num: usize, definition_id: DefinitionI
 
}
 

	
 
fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph: &str) -> (Option<i32>, String) {
 
    use DefinedTypeVariant::*;
 

	
 
    let type_def = ctx.types.get_base_definition(&definition_id).unwrap();
 

	
 
    // Note: full_buffer is just for error reporting
 
    let mut full_buffer = String::new();
 
    let mut has_match = None;
0 comments (0 inline, 0 general)