swamp_code_gen/
alloc_util.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use crate::alloc::{FrameMemoryRegion, ScopeAllocator};
7use seq_map::SeqMap;
8use swamp_types::{AnonymousStructType, EnumVariantType, Type};
9use swamp_vm_types::{
10    FLOAT_SIZE, INT_SIZE, MAP_REFERENCE_SIZE, MAP_SIZE, MemoryAlignment, MemoryOffset, MemorySize,
11    STR_SIZE, VEC_REFERENCE_SIZE,
12};
13use tracing::{error, info};
14
15pub fn layout_struct(anon_struct: &AnonymousStructType) -> (MemorySize, MemoryAlignment) {
16    let mut calculated_offset = MemoryOffset(0);
17    let mut largest_alignment = MemoryAlignment::U8;
18    for (_name, field) in &anon_struct.field_name_sorted_fields {
19        let (field_size, field_alignment) = type_size_and_alignment(&field.field_type);
20        if field_alignment.greater_than(largest_alignment) {
21            largest_alignment = field_alignment;
22        }
23        calculated_offset.space(field_size, field_alignment);
24    }
25
26    let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
27
28    (total_offset.as_size(), largest_alignment)
29}
30
31#[must_use]
32pub fn layout_tuple(types: &Vec<Type>) -> (MemorySize, MemoryAlignment) {
33    let mut calculated_offset = MemoryOffset(0);
34    let mut largest_alignment = MemoryAlignment::U8;
35    for ty in types {
36        let (field_size, field_alignment) = type_size_and_alignment(&ty);
37        if field_alignment.greater_than(largest_alignment) {
38            largest_alignment = field_alignment;
39        }
40        calculated_offset.space(field_size, field_alignment);
41    }
42    let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
43    (total_offset.as_size(), largest_alignment)
44}
45
46#[must_use]
47pub fn layout_tuple_elements(
48    types: &Vec<Type>,
49) -> (MemorySize, MemoryAlignment, Vec<(MemoryOffset, MemorySize)>) {
50    let mut calculated_offset = MemoryOffset(0);
51    let mut largest_alignment = MemoryAlignment::U8;
52
53    let mut elements = Vec::new();
54    for ty in types {
55        let (field_size, field_alignment) = type_size_and_alignment(&ty);
56        if field_alignment.greater_than(largest_alignment) {
57            largest_alignment = field_alignment;
58        }
59        elements.push((calculated_offset, field_size));
60        calculated_offset.space(field_size, field_alignment);
61    }
62    let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
63    (total_offset.as_size(), largest_alignment, elements)
64}
65
66pub fn layout_union(variants: &SeqMap<String, EnumVariantType>) -> (MemorySize, MemoryAlignment) {
67    let mut max_variant_alignment = MemoryAlignment::U8;
68    let mut max_variant_size = MemorySize(0);
69    let mut calculated_offset = MemoryOffset(0);
70    for (_name, variant) in variants {
71        let (variant_size, variant_alignment) = match variant {
72            EnumVariantType::Struct(anon_struct) => layout_struct(&anon_struct.anon_struct),
73            EnumVariantType::Tuple(types) => layout_tuple(&types.fields_in_order),
74            EnumVariantType::Nothing(_) => (MemorySize(0), MemoryAlignment::U8),
75        };
76
77        if variant_alignment.greater_than(max_variant_alignment) {
78            max_variant_alignment = variant_alignment;
79        }
80
81        if variant_size.0 > max_variant_size.0 {
82            max_variant_size = variant_size;
83        }
84    }
85
86    (max_variant_size, max_variant_alignment)
87}
88
89pub fn is_vec(ty: &Type) -> Option<(MemorySize, MemoryAlignment)> {
90    match ty {
91        Type::NamedStruct(named_struct) => {
92            if named_struct.module_path == vec!["core-0.0.0".to_string()]
93                && named_struct.assigned_name.starts_with("Vec<")
94            {
95                Some((MemorySize(VEC_REFERENCE_SIZE), MemoryAlignment::U16))
96            } else {
97                None
98            }
99        }
100        _ => None,
101    }
102}
103
104pub fn is_map(ty: &Type) -> Option<(MemorySize, MemoryAlignment)> {
105    match ty {
106        Type::NamedStruct(named_struct) => {
107            if named_struct.module_path == vec!["core-0.0.0".to_string()]
108                && named_struct.assigned_name.starts_with("Map<")
109            {
110                Some((MemorySize(MAP_SIZE), MemoryAlignment::U16))
111            } else {
112                None
113            }
114        }
115        _ => None,
116    }
117}
118
119pub fn type_size_and_alignment(ty: &Type) -> (MemorySize, MemoryAlignment) {
120    match ty {
121        Type::Int => (MemorySize(INT_SIZE), MemoryAlignment::U32),
122        Type::Float => (MemorySize(FLOAT_SIZE), MemoryAlignment::U32),
123        Type::String => (MemorySize(STR_SIZE), MemoryAlignment::U16),
124        Type::Bool => (MemorySize(1), MemoryAlignment::U8),
125        Type::Unit => (MemorySize(0), MemoryAlignment::U8),
126        Type::Never => (MemorySize(0), MemoryAlignment::U8),
127        Type::Tuple(types) => layout_tuple(types),
128        Type::NamedStruct(named_struct) => {
129            if named_struct.module_path == vec!["core-0.0.0".to_string()]
130                && named_struct.assigned_name.starts_with("Vec<")
131            {
132                (MemorySize(VEC_REFERENCE_SIZE), MemoryAlignment::U16)
133            } else if named_struct.module_path == vec!["core-0.0.0".to_string()]
134                && named_struct.assigned_name.starts_with("Map<")
135            {
136                (MemorySize(MAP_REFERENCE_SIZE), MemoryAlignment::U16)
137            } else {
138                type_size_and_alignment(&Type::AnonymousStruct(
139                    named_struct.anon_struct_type.clone(),
140                ))
141            }
142        }
143        Type::Slice(value_type) => type_size_and_alignment(value_type),
144        Type::SlicePair(key_type, value_type) => {
145            layout_tuple(&vec![*key_type.clone(), *value_type.clone()])
146        }
147        Type::AnonymousStruct(anon_struct) => layout_struct(anon_struct),
148        Type::Enum(enum_type) => {
149            let (offset, alignment) = layout_union(&enum_type.variants);
150
151            let alignment_octets: usize = alignment.into();
152
153            (MemorySize(offset.0 + alignment_octets as u16), alignment)
154        }
155        Type::Function(_) => (MemorySize(2), MemoryAlignment::U16),
156        Type::Optional(inner_type) => {
157            let (offset, alignment) = type_size_and_alignment(inner_type);
158
159            let alignment_octets: usize = alignment.into();
160
161            (MemorySize(offset.0 + alignment_octets as u16), alignment)
162        }
163        Type::Generic(a, b) => {
164            error!(?a, ?b, "generic can not be generated");
165            panic!("generic is not supported")
166        }
167        Type::MutableReference(referenced_type) => type_size_and_alignment(referenced_type),
168        Type::Blueprint(_) => panic!("not supported"),
169        Type::Variable(_) => panic!("not supported"),
170        Type::External(_) => todo!(),
171    }
172}
173
174pub fn reserve_space_for_type(ty: &Type, allocator: &mut ScopeAllocator) -> FrameMemoryRegion {
175    let (size, alignment) = type_size_and_alignment(ty);
176
177    allocator.reserve(size, alignment)
178}