swamp_vm_layout/
lib.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//! Layouts analyzed into Vm Types (`BasicType`)
6
7use seq_map::SeqMap;
8use std::cmp::max;
9use std::rc::Rc;
10use swamp_symbol::TopLevelSymbolId;
11use swamp_types::prelude::{AnonymousStructType, EnumType, EnumVariantType, NamedStructType};
12use swamp_types::{TypeId, TypeKind, TypeRef};
13use swamp_vm_types::types::{
14    BasicType, BasicTypeId, BasicTypeKind, BasicTypeRef, OffsetMemoryItem, StructType, TaggedUnion,
15    TaggedUnionVariant, TupleType,
16};
17use swamp_vm_types::{
18    adjust_size_to_alignment, align_to, CountU16, MemoryAlignment, MemoryOffset,
19    MemorySize, ANY_HEADER_ALIGNMENT, ANY_HEADER_SIZE, GRID_HEADER_ALIGNMENT, GRID_HEADER_SIZE, MAP_HEADER_ALIGNMENT,
20    PTR_ALIGNMENT, PTR_SIZE, STRING_PTR_ALIGNMENT, STRING_PTR_SIZE,
21    VEC_HEADER_ALIGNMENT, VEC_HEADER_SIZE,
22};
23
24#[derive(Clone)]
25pub struct LayoutCache {
26    pub id_to_layout: SeqMap<TypeId, BasicTypeRef>,
27    pub kind_to_layout: SeqMap<TypeKind, BasicTypeRef>,
28}
29
30impl LayoutCache {}
31
32impl Default for LayoutCache {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl LayoutCache {
39    #[must_use]
40    pub fn new() -> Self {
41        Self {
42            id_to_layout: SeqMap::default(),
43            kind_to_layout: SeqMap::default(),
44        }
45    }
46
47    #[must_use]
48    pub fn layout(&mut self, analyzed_type: &TypeRef) -> BasicTypeRef {
49        // First check if we already have a layout for this type ID
50        if let Some(x) = self.id_to_layout.get(&analyzed_type.id) {
51            return x.clone();
52        }
53
54        // Check if we already have a layout for this kind of type
55        if let Some(existing_layout) = self.kind_to_layout.get(&analyzed_type.kind) {
56            // For deduplication, we reuse the existing layout directly
57            // This ensures pointer equality for structurally identical types
58            let _ = self
59                .id_to_layout
60                .insert(analyzed_type.id, existing_layout.clone());
61            return existing_layout.clone();
62        }
63
64        let basic_type = self.layout_type(analyzed_type);
65
66        let _ = self
67            .id_to_layout
68            .insert(analyzed_type.id, basic_type.clone());
69
70        // Also store in kind_to_layout for future deduplication
71        let _ = self
72            .kind_to_layout
73            .insert((*analyzed_type.kind).clone(), basic_type.clone());
74
75        basic_type
76    }
77
78    #[must_use]
79    fn layout_tagged_union(variants: &[TaggedUnionVariant], name: &str) -> TaggedUnion {
80        let num_variants = variants.len();
81        let (tag_size, tag_alignment) = if num_variants <= 0xFF {
82            (MemorySize(1), MemoryAlignment::U8)
83        } else if num_variants <= 0xFFFF {
84            (MemorySize(2), MemoryAlignment::U16)
85        } else {
86            (MemorySize(4), MemoryAlignment::U32)
87        };
88
89        // First pass: Find maximum payload size and alignment
90        let max_payload_size = variants
91            .iter()
92            .map(|v| v.ty.total_size)
93            .max()
94            .unwrap_or(MemorySize(0));
95        let max_payload_alignment = variants
96            .iter()
97            .map(|v| v.ty.max_alignment)
98            .max()
99            .unwrap_or(MemoryAlignment::U8);
100
101        // Second pass: Layout using maximum alignment
102        let max_alignment = max(tag_alignment, max_payload_alignment);
103        let payload_offset = align_to(MemoryOffset(tag_size.0), max_payload_alignment);
104
105        let complete_size_before_alignment = MemorySize(payload_offset.0 + max_payload_size.0);
106        let total_size = adjust_size_to_alignment(complete_size_before_alignment, max_alignment);
107
108        TaggedUnion {
109            name: name.to_string(),
110            tag_offset: MemoryOffset(0),
111            tag_size,
112            tag_alignment,
113            payload_offset,
114            payload_max_size: max_payload_size,
115            max_payload_alignment,
116            total_size,
117            max_alignment,
118            variants: variants.to_vec(),
119        }
120    }
121
122    #[allow(clippy::too_many_lines)]
123    #[must_use]
124    pub fn layout_enum_into_tagged_union(
125        &mut self,
126        name: &str,
127        v: &[EnumVariantType],
128    ) -> TaggedUnion {
129        let variant_layouts: Vec<_> = v
130            .iter()
131            .map(|variant| {
132                let gen_payload_type = self.layout_type(&variant.payload_type);
133
134                TaggedUnionVariant {
135                    name: variant.common.assigned_name.clone(),
136                    ty: gen_payload_type,
137                }
138            })
139            .collect();
140
141        Self::layout_tagged_union(&variant_layouts, name)
142    }
143
144    #[must_use]
145    pub fn layout_enum(
146        &mut self,
147        name: &str,
148        variants: &[EnumVariantType],
149        type_id: TypeId,
150        symbol_id: TopLevelSymbolId,
151    ) -> BasicTypeRef {
152        // Check if we already have a layout for this kind
153        let enum_kind = TypeKind::Enum(EnumType::new(
154            source_map_node::Node::default(),
155            name,
156            symbol_id,
157            vec![String::new()],
158        ));
159        if let Some(existing_layout) = self.kind_to_layout.get(&enum_kind) {
160            return existing_layout.clone();
161        }
162
163        let tagged_union = self.layout_enum_into_tagged_union(name, variants);
164
165        let basic_type = Rc::new(BasicType {
166            id: BasicTypeId(type_id.inner()),
167            total_size: tagged_union.total_size,
168            max_alignment: tagged_union.max_alignment,
169            kind: BasicTypeKind::TaggedUnion(tagged_union),
170        });
171
172        // Store in kind_to_layout
173        let _ = self.kind_to_layout.insert(enum_kind, basic_type.clone());
174
175        basic_type
176    }
177
178    #[must_use]
179    fn layout_vec_like(
180        &mut self,
181        element_type: &TypeRef,
182        capacity: usize,
183    ) -> (BasicTypeRef, MemorySize, MemoryAlignment) {
184        let element_type_basic = self.layout_type(element_type);
185        let (mem_size, mem_alignment) =
186            self.layout_vec_like_from_basic(&element_type_basic, capacity);
187
188        (element_type_basic, mem_size, mem_alignment)
189    }
190
191    #[must_use]
192    fn layout_vec_like_from_basic(
193        &mut self,
194        element_type_basic: &BasicTypeRef,
195        capacity: usize,
196    ) -> (MemorySize, MemoryAlignment) {
197        let total_size =
198            element_type_basic.total_size.0 as usize * capacity + VEC_HEADER_SIZE.0 as usize;
199        let max_alignment = max(element_type_basic.max_alignment, MemoryAlignment::U32);
200
201        (MemorySize(total_size as u32), max_alignment)
202    }
203
204    /// Computes the memory layout for a type in the target architecture.
205    ///
206    /// In compiler terminology:
207    ///
208    /// - "layout" determines size, alignment, and field offsets of types
209    /// - "materialization" refers to how types are represented in memory
210    /// - "lowering" is the process of mapping source types to machine types
211    ///
212    /// This function performs type lowering by mapping high-level types to their
213    /// concrete memory representations, handling:
214    ///
215    /// - Primitive, scalar types (integers, floats, booleans)
216    /// - Aggregate types (structs, tuples, enums)
217    /// - Reference types (pointers, slices)
218    /// - Collection types (vectors, maps)
219    ///
220    /// The layout process considers:
221    ///
222    /// - Size: Total bytes needed for the type
223    /// - Alignment: Memory boundary requirements
224    /// - Padding: Gaps needed for proper field alignment
225    /// - ABI: Target architecture requirements
226    ///
227    /// # Panics
228    ///
229    #[allow(clippy::too_many_lines)]
230    #[must_use]
231    fn layout_type(&mut self, ty: &TypeRef) -> BasicTypeRef {
232        // First check if we already have a layout for this type ID
233        if let Some(x) = self.id_to_layout.get(&ty.id) {
234            return x.clone();
235        }
236
237        // Check if we already have a layout for this kind of type
238        if let Some(existing_layout) = self.kind_to_layout.get(&ty.kind) {
239            // For deduplication, we need to create a new BasicType with the same structure
240            // but with the original TypeId, so that pointer equality works for the same
241            // structural types, but we still have separate entries for each TypeId
242            let new_basic_type = Rc::new(BasicType {
243                id: BasicTypeId(ty.id.inner()),
244                total_size: existing_layout.total_size,
245                max_alignment: existing_layout.max_alignment,
246                kind: existing_layout.kind.clone(),
247            });
248
249            // Store the mapping from this type ID to the new layout
250            let _ = self.id_to_layout.insert(ty.id, new_basic_type.clone());
251
252            // For nested types, we need to properly track all component types
253            // This is essential for the deduplication to work correctly
254            match &*ty.kind {
255                TypeKind::AnonymousStruct(struct_type) => {
256                    // Process each field type
257                    for field in struct_type.field_name_sorted_fields.values() {
258                        let field_type = &field.field_type;
259                        let field_layout = self.layout(field_type);
260                        let _ = self.id_to_layout.insert(field_type.id, field_layout);
261                    }
262                }
263
264                TypeKind::NamedStruct(named_struct) => {
265                    // Process each field type in the anonymous struct
266                    if let TypeKind::AnonymousStruct(anon_struct) =
267                        &*named_struct.anon_struct_type.kind
268                    {
269                        for field in anon_struct.field_name_sorted_fields.values() {
270                            let field_type = &field.field_type;
271                            let field_layout = self.layout(field_type);
272                            let _ = self.id_to_layout.insert(field_type.id, field_layout);
273                        }
274                    }
275                }
276
277                TypeKind::Tuple(tuple_types) => {
278                    // Process each tuple element type
279                    for elem_type in tuple_types {
280                        let elem_layout = self.layout(elem_type);
281                        let _ = self.id_to_layout.insert(elem_type.id, elem_layout);
282                    }
283                }
284                _ => {}
285            }
286
287            return new_basic_type;
288        }
289
290        let basic_type = match &*ty.kind {
291            TypeKind::Never => {
292                create_basic_type(ty.id, BasicTypeKind::U8, MemorySize(0), MemoryAlignment::U8)
293            }
294            TypeKind::Byte => {
295                create_basic_type(ty.id, BasicTypeKind::U8, MemorySize(1), MemoryAlignment::U8)
296            }
297            TypeKind::Codepoint => create_basic_type(
298                ty.id,
299                BasicTypeKind::U32,
300                MemorySize(4),
301                MemoryAlignment::U32,
302            ),
303            TypeKind::Int => create_basic_type(
304                ty.id,
305                BasicTypeKind::S32,
306                MemorySize(4),
307                MemoryAlignment::U32,
308            ),
309
310            TypeKind::Float => create_basic_type(
311                ty.id,
312                BasicTypeKind::Fixed32,
313                MemorySize(4),
314                MemoryAlignment::U32,
315            ),
316
317            TypeKind::Bool => {
318                create_basic_type(ty.id, BasicTypeKind::B8, MemorySize(1), MemoryAlignment::U8)
319            }
320
321            TypeKind::String(byte, char) => create_basic_type(
322                ty.id,
323                BasicTypeKind::StringView {
324                    byte: self.layout(byte),
325                    char: self.layout(char),
326                },
327                STRING_PTR_SIZE,
328                STRING_PTR_ALIGNMENT,
329            ),
330
331            TypeKind::AnonymousStruct(struct_type) => {
332                self.layout_struct(struct_type, "anonymous", ty.id)
333            }
334
335            TypeKind::NamedStruct(named_struct) => self.layout_named_struct(named_struct, ty.id),
336
337            TypeKind::Tuple(tuple_types) => self.layout_tuple(tuple_types, ty.id),
338
339            TypeKind::Optional(inner_type) => self.layout_optional_type(inner_type, ty.id),
340
341            TypeKind::Enum(enum_type) => {
342                let variants = enum_type.variants.values().cloned().collect::<Vec<_>>();
343                self.layout_enum(&enum_type.assigned_name, &variants, ty.id, enum_type.symbol_id)
344            }
345
346            TypeKind::FixedCapacityAndLengthArray(element_type, capacity) => {
347                let (element_layout, total_size, max_alignment) =
348                    self.layout_vec_like(element_type, *capacity);
349
350                let array_type = Rc::new(BasicType {
351                    id: BasicTypeId(ty.id.inner()),
352                    kind: BasicTypeKind::FixedCapacityArray(element_layout.clone(), *capacity),
353                    total_size,
354                    max_alignment,
355                });
356
357                // Also store the element type in id_to_layout
358                let _ = self.id_to_layout.insert(element_type.id, element_layout);
359
360                array_type
361            }
362
363            TypeKind::StringStorage(byte_type, char_type, capacity) => {
364                let (element_layout, total_size, max_alignment) =
365                    self.layout_vec_like(byte_type, *capacity);
366
367                let array_type = Rc::new(BasicType {
368                    id: BasicTypeId(ty.id.inner()),
369                    kind: BasicTypeKind::StringStorage {
370                        element_type: element_layout.clone(),
371                        char: self.layout(char_type),
372                        capacity: *capacity,
373                    },
374                    total_size,
375                    max_alignment,
376                });
377
378                // Also store the element type in id_to_layout
379                let _ = self.id_to_layout.insert(byte_type.id, element_layout);
380
381                array_type
382            }
383
384            TypeKind::Any => create_basic_type(
385                ty.id,
386                BasicTypeKind::Any,
387                ANY_HEADER_SIZE,
388                ANY_HEADER_ALIGNMENT,
389            ),
390
391            TypeKind::DynamicLengthVecView(element_type) => {
392                let (element_layout, _, _) = self.layout_vec_like(element_type, 0);
393
394                let vec_type = Rc::new(BasicType {
395                    id: BasicTypeId(ty.id.inner()),
396                    kind: BasicTypeKind::DynamicLengthVecView(element_layout.clone()),
397                    total_size: PTR_SIZE,
398                    max_alignment: PTR_ALIGNMENT,
399                });
400
401                let _ = self.id_to_layout.insert(element_type.id, element_layout);
402
403                vec_type
404            }
405
406            TypeKind::VecStorage(element_type, capacity) => {
407                let (element_layout, total_size, element_alignment) =
408                    self.layout_vec_like(element_type, *capacity);
409
410                let storage_type = Rc::new(BasicType {
411                    id: BasicTypeId(ty.id.inner()),
412                    kind: BasicTypeKind::VecStorage(element_layout.clone(), *capacity),
413                    total_size,
414                    max_alignment: max(VEC_HEADER_ALIGNMENT, element_alignment),
415                });
416
417                let _ = self.id_to_layout.insert(element_type.id, element_layout);
418
419                storage_type
420            }
421
422            TypeKind::DynamicLengthMapView(key_type, value_type) => {
423                // Layout key type
424                let key_layout = self.layout(key_type);
425                let _ = self.id_to_layout.insert(key_type.id, key_layout.clone());
426
427                // Layout value type
428                let value_layout = self.layout(value_type);
429                let _ = self
430                    .id_to_layout
431                    .insert(value_type.id, value_layout.clone());
432
433                let key_item = OffsetMemoryItem {
434                    offset: MemoryOffset(0),
435                    size: key_layout.total_size,
436                    name: "key".to_string(),
437                    ty: key_layout.clone(),
438                };
439
440                let value_offset = align_to(
441                    MemoryOffset(key_layout.total_size.0),
442                    value_layout.max_alignment,
443                );
444
445                let value_item = OffsetMemoryItem {
446                    offset: value_offset,
447                    size: value_layout.total_size,
448                    name: "value".to_string(),
449                    ty: value_layout.clone(),
450                };
451
452                Rc::new(BasicType {
453                    id: BasicTypeId(ty.id.inner()),
454                    kind: BasicTypeKind::DynamicLengthMapView(
455                        Box::new(key_item),
456                        Box::new(value_item),
457                    ),
458                    total_size: PTR_SIZE,
459                    max_alignment: PTR_ALIGNMENT,
460                })
461            }
462
463            TypeKind::MapStorage(key_type, value_type, logical_limit) => {
464                // Layout key type
465                let key_layout = self.layout(key_type);
466                let _ = self.id_to_layout.insert(key_type.id, key_layout.clone());
467
468                // Layout value type
469                let value_layout = self.layout(value_type);
470                let _ = self
471                    .id_to_layout
472                    .insert(value_type.id, value_layout.clone());
473
474                let logical_limit = *logical_limit;
475
476                let (_bucket_layout, map_init) = hashmap_mem::layout(
477                    key_layout.total_size.0,
478                    key_layout.max_alignment.into(),
479                    value_layout.total_size.0,
480                    value_layout.max_alignment.into(),
481                    logical_limit as u16,
482                );
483                let total_size = MemorySize(map_init.total_size);
484
485                Rc::new(BasicType {
486                    id: BasicTypeId(ty.id.inner()),
487                    kind: BasicTypeKind::MapStorage {
488                        key_type: key_layout,
489                        logical_limit,
490                        capacity: CountU16(map_init.capacity),
491                        value_type: value_layout,
492                    },
493                    total_size,
494                    max_alignment: MAP_HEADER_ALIGNMENT,
495                })
496            }
497
498            TypeKind::Range(_range_struct) => create_basic_type(
499                ty.id,
500                BasicTypeKind::InternalRangeHeader,
501                MemorySize(12),
502                MemoryAlignment::U32,
503            ),
504
505            TypeKind::GridView(element_type) => {
506                let element_layout = self.layout(element_type);
507                let _ = self
508                    .id_to_layout
509                    .insert(element_type.id, element_layout.clone());
510
511                Rc::new(BasicType {
512                    id: BasicTypeId(ty.id.inner()),
513                    kind: BasicTypeKind::GridView(element_layout),
514                    total_size: PTR_SIZE,
515                    max_alignment: PTR_ALIGNMENT,
516                })
517            }
518
519            TypeKind::GridStorage(element_type, width, height) => {
520                let element_layout = self.layout(element_type);
521                let _ = self
522                    .id_to_layout
523                    .insert(element_type.id, element_layout.clone());
524
525                let element_size = element_layout.total_size;
526                let element_alignment = element_layout.max_alignment;
527
528                Rc::new(BasicType {
529                    id: BasicTypeId(ty.id.inner()),
530                    kind: BasicTypeKind::GridStorage(element_layout, *width, *height),
531                    total_size: MemorySize(
532                        GRID_HEADER_SIZE.0 + element_size.0 * (*width as u32) * (*height as u32),
533                    ),
534                    max_alignment: max(GRID_HEADER_ALIGNMENT, element_alignment),
535                })
536            }
537
538            TypeKind::SliceView(element_type) => {
539                let element_layout = self.layout(element_type);
540                let _ = self
541                    .id_to_layout
542                    .insert(element_type.id, element_layout.clone());
543
544                Rc::new(BasicType {
545                    id: BasicTypeId(ty.id.inner()),
546                    kind: BasicTypeKind::SliceView(element_layout),
547                    total_size: PTR_SIZE,
548                    max_alignment: PTR_ALIGNMENT,
549                })
550            }
551
552            TypeKind::SparseStorage(element_type, capacity) => {
553                let element_layout = self.layout(element_type);
554                let size = sparse_mem::layout_size(*capacity as u16, element_layout.total_size.0);
555
556                Rc::new(BasicType {
557                    id: BasicTypeId(ty.id.inner()),
558                    kind: BasicTypeKind::SparseStorage(element_layout, *capacity),
559                    total_size: MemorySize(size as u32),
560                    max_alignment: MemoryAlignment::U64,
561                })
562            }
563
564            TypeKind::SparseView(element_type) => {
565                let element_layout = self.layout(element_type);
566                let _ = self
567                    .id_to_layout
568                    .insert(element_type.id, element_layout.clone());
569
570                Rc::new(BasicType {
571                    id: BasicTypeId(ty.id.inner()),
572                    kind: BasicTypeKind::SparseView(element_layout),
573                    total_size: PTR_SIZE,
574                    max_alignment: PTR_ALIGNMENT,
575                })
576            }
577
578            TypeKind::StackStorage(element_type, capacity) => {
579                let (element_layout, total_size, _max_alignment) =
580                    self.layout_vec_like(element_type, *capacity);
581
582                let storage_type = Rc::new(BasicType {
583                    id: BasicTypeId(ty.id.inner()),
584                    kind: BasicTypeKind::StackStorage(element_layout.clone(), *capacity),
585                    total_size,
586                    max_alignment: VEC_HEADER_ALIGNMENT,
587                });
588
589                let _ = self.id_to_layout.insert(element_type.id, element_layout);
590
591                storage_type
592            }
593
594            TypeKind::StackView(element_type) => {
595                let element_layout = self.layout(element_type);
596                let _ = self
597                    .id_to_layout
598                    .insert(element_type.id, element_layout.clone());
599
600                Rc::new(BasicType {
601                    id: BasicTypeId(ty.id.inner()),
602                    kind: BasicTypeKind::DynamicLengthVecView(element_layout),
603                    total_size: PTR_SIZE,
604                    max_alignment: PTR_ALIGNMENT,
605                })
606            }
607
608            TypeKind::QueueStorage(element_type, capacity) => {
609                let (element_layout, total_size, _max_alignment) =
610                    self.layout_vec_like(element_type, *capacity);
611
612                let storage_type = Rc::new(BasicType {
613                    id: BasicTypeId(ty.id.inner()),
614                    kind: BasicTypeKind::QueueStorage(element_layout.clone(), *capacity),
615                    total_size,
616                    max_alignment: VEC_HEADER_ALIGNMENT,
617                });
618
619                let _ = self.id_to_layout.insert(element_type.id, element_layout);
620
621                storage_type
622            }
623
624            TypeKind::QueueView(element_type) => {
625                let element_layout = self.layout(element_type);
626                let _ = self
627                    .id_to_layout
628                    .insert(element_type.id, element_layout.clone());
629
630                Rc::new(BasicType {
631                    id: BasicTypeId(ty.id.inner()),
632                    kind: BasicTypeKind::DynamicLengthVecView(element_layout),
633                    total_size: PTR_SIZE,
634                    max_alignment: PTR_ALIGNMENT,
635                })
636            }
637
638            TypeKind::Function(_) => {
639                panic!("function types can not be laid out")
640            }
641
642            TypeKind::Unit => create_basic_type(
643                ty.id,
644                BasicTypeKind::Empty,
645                MemorySize(0),
646                MemoryAlignment::U8,
647            ),
648        };
649
650        // Store in both caches
651        let _ = self.id_to_layout.insert(ty.id, basic_type.clone());
652        let _ = self
653            .kind_to_layout
654            .insert((*ty.kind).clone(), basic_type.clone());
655
656        basic_type
657    }
658
659    fn layout_named_struct(
660        &mut self,
661        named_struct_type: &NamedStructType,
662        type_id: TypeId,
663    ) -> BasicTypeRef {
664        // Check if we already have a layout for this kind
665        let struct_kind = TypeKind::NamedStruct(named_struct_type.clone());
666        if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
667            return existing_layout.clone();
668        }
669
670        // Extract AnonymousStructType from the TypeRef
671        let anon_struct = match &*named_struct_type.anon_struct_type.kind {
672            TypeKind::AnonymousStruct(anon_struct) => anon_struct,
673            _ => panic!("Expected AnonymousStruct in NamedStructType"),
674        };
675
676        let inner_struct = self.layout_struct_type(anon_struct, &named_struct_type.assigned_name);
677
678        // Use the provided TypeId
679        let basic_type = Rc::new(BasicType {
680            id: BasicTypeId(type_id.inner()), // Use the provided type ID
681            total_size: inner_struct.total_size,
682            max_alignment: inner_struct.max_alignment,
683            kind: BasicTypeKind::Struct(inner_struct),
684        });
685
686        // Store in kind_to_layout for future deduplication
687        let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
688
689        basic_type
690    }
691
692    #[must_use]
693    pub fn layout_struct_type(
694        &mut self,
695        struct_type: &AnonymousStructType,
696        name: &str,
697    ) -> StructType {
698        // First pass: Layout all field types and determine maximum alignment requirement
699        let mut field_layouts = Vec::with_capacity(struct_type.field_name_sorted_fields.len());
700        let mut max_alignment = MemoryAlignment::U8;
701
702        for (field_name, field_type) in &struct_type.field_name_sorted_fields {
703            // Use layout instead of layout_type to ensure proper caching
704            let field_layout = self.layout(&field_type.field_type);
705            check_type_size(&field_layout, &format!("field {name}::{field_name}"));
706
707            // Make sure the field type is in the id_to_layout map
708            let _ = self
709                .id_to_layout
710                .insert(field_type.field_type.id, field_layout.clone());
711
712            if field_layout.max_alignment > max_alignment {
713                max_alignment = field_layout.max_alignment;
714            }
715
716            field_layouts.push((field_name.clone(), field_layout));
717        }
718
719        // Second pass: Layout fields using the maximum alignment
720        let mut offset = MemoryOffset(0);
721        let mut items = Vec::with_capacity(field_layouts.len());
722
723        for (field_name, field_layout) in field_layouts {
724            offset = align_to(offset, field_layout.max_alignment);
725
726            items.push(OffsetMemoryItem {
727                offset,
728                size: field_layout.total_size,
729                name: field_name,
730                ty: field_layout.clone(),
731            });
732
733            offset = offset + field_layout.total_size;
734        }
735
736        let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
737
738        StructType {
739            name: name.to_string(),
740            fields: items,
741            total_size,
742            max_alignment,
743        }
744    }
745
746    pub fn layout_struct(
747        &mut self,
748        struct_type: &AnonymousStructType,
749        name: &str,
750        type_id: TypeId,
751    ) -> BasicTypeRef {
752        // Always process each field's type to ensure it's in the cache
753        for (_field_name, struct_field) in &struct_type.field_name_sorted_fields {
754            let field_type = &struct_field.field_type;
755            let _field_layout = self.layout(field_type);
756
757            // The layout method already handles storing in both caches
758        }
759
760        // Check if we already have a layout for this kind
761        let struct_kind = TypeKind::AnonymousStruct(struct_type.clone());
762        if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
763            // Store the mapping from this type ID to the existing layout
764            let _ = self.id_to_layout.insert(type_id, existing_layout.clone());
765            return existing_layout.clone();
766        }
767
768        let struct_layout = self.layout_struct_type(struct_type, name);
769
770        // Use the provided type ID
771        let struct_id = type_id;
772
773        let basic_type = Rc::new(BasicType {
774            id: BasicTypeId(struct_id.inner()),
775            total_size: struct_layout.total_size,
776            max_alignment: struct_layout.max_alignment,
777            kind: BasicTypeKind::Struct(struct_layout),
778        });
779
780        // Store in both caches
781        let _ = self.id_to_layout.insert(struct_id, basic_type.clone());
782        let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
783
784        basic_type
785    }
786
787    #[must_use]
788    pub fn layout_optional_type(&mut self, inner_type: &TypeRef, type_id: TypeId) -> BasicTypeRef {
789        // Check if we already have a layout for this kind
790        let optional_kind = TypeKind::Optional(inner_type.clone());
791        if let Some(existing_layout) = self.kind_to_layout.get(&optional_kind) {
792            assert!(matches!(&existing_layout.kind, BasicTypeKind::Optional(_)));
793            return existing_layout.clone();
794        }
795
796        // Layout the inner type first
797        let inner_layout = self.layout(inner_type);
798
799        // Store the inner type in both caches
800        let _ = self
801            .id_to_layout
802            .insert(inner_type.id, inner_layout.clone());
803        let _ = self
804            .kind_to_layout
805            .insert((*inner_type.kind).clone(), inner_layout);
806
807        // Create the optional type
808        let optional_union = self.layout_optional_type_items(inner_type);
809
810        // Use the provided type ID
811        let optional_id = type_id;
812
813        let basic_type = Rc::new(BasicType {
814            id: BasicTypeId(optional_id.inner()),
815            total_size: optional_union.total_size,
816            max_alignment: optional_union.max_alignment,
817            kind: BasicTypeKind::Optional(optional_union),
818        });
819
820        // Store in both caches
821        let _ = self.id_to_layout.insert(optional_id, basic_type.clone());
822        let _ = self
823            .kind_to_layout
824            .insert(optional_kind, basic_type.clone());
825
826        basic_type
827    }
828
829    #[must_use]
830    pub fn layout_optional_type_items(&mut self, inner_type: &TypeRef) -> TaggedUnion {
831        let gen_type = self.layout_type(inner_type);
832
833        let payload_tagged_variant = TaggedUnionVariant {
834            name: "Some".to_string(),
835            ty: gen_type,
836        };
837
838        let none_tagged_variant = TaggedUnionVariant {
839            name: "None".to_string(),
840            ty: Rc::new(BasicType {
841                id: BasicTypeId(0),
842                kind: BasicTypeKind::Empty,
843                total_size: MemorySize(0),
844                max_alignment: MemoryAlignment::U8,
845            }),
846        };
847
848        Self::layout_tagged_union(&[none_tagged_variant, payload_tagged_variant], "Maybe")
849    }
850
851    #[must_use]
852    pub fn layout_tuple_items(&mut self, types: &[TypeRef]) -> TupleType {
853        // First pass: Determine maximum alignment requirement
854        let mut max_alignment = MemoryAlignment::U8;
855        for ty in types {
856            // Use layout instead of layout_type to ensure proper caching
857            let elem_layout = self.layout(ty);
858
859            // Make sure the element type is in the id_to_layout map
860            let _ = self.id_to_layout.insert(ty.id, elem_layout.clone());
861
862            if elem_layout.max_alignment > max_alignment {
863                max_alignment = elem_layout.max_alignment;
864            }
865        }
866
867        // Second pass: Layout fields using the maximum alignment
868        let mut offset = MemoryOffset(0);
869        let mut items = Vec::with_capacity(types.len());
870
871        for (i, ty) in types.iter().enumerate() {
872            // Reuse the layout from the cache
873            let elem_layout = self.layout(ty);
874
875            offset = align_to(offset, elem_layout.max_alignment);
876
877            items.push(OffsetMemoryItem {
878                offset,
879                size: elem_layout.total_size,
880                name: i.to_string(),
881                ty: elem_layout.clone(),
882            });
883
884            offset = offset + elem_layout.total_size;
885        }
886
887        // Ensure total size is aligned to max_alignment
888        let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
889
890        TupleType {
891            fields: items,
892            total_size,
893            max_alignment,
894        }
895    }
896
897    #[must_use]
898    pub fn layout_tuple(&mut self, types: &[TypeRef], tuple_id: TypeId) -> BasicTypeRef {
899        // Always process each inner type to ensure it's in the cache
900        for ty in types {
901            let inner_layout = self.layout(ty);
902            let _ = self.id_to_layout.insert(ty.id, inner_layout.clone());
903            let _ = self
904                .kind_to_layout
905                .insert((*ty.kind).clone(), inner_layout.clone());
906        }
907
908        // Check if we already have a layout for this kind
909        let tuple_kind = TypeKind::Tuple(types.to_vec());
910        if let Some(existing_layout) = self.kind_to_layout.get(&tuple_kind) {
911            // Store the mapping from this type ID to the existing layout
912            let _ = self.id_to_layout.insert(tuple_id, existing_layout.clone());
913            return existing_layout.clone();
914        }
915
916        let tuple_layout = self.layout_tuple_items(types);
917
918        let basic_type = Rc::new(BasicType {
919            id: BasicTypeId(tuple_id.inner()),
920            total_size: tuple_layout.total_size,
921            max_alignment: tuple_layout.max_alignment,
922            kind: BasicTypeKind::Tuple(tuple_layout),
923        });
924
925        // Store in both caches
926        let _ = self.id_to_layout.insert(tuple_id, basic_type.clone());
927        let _ = self.kind_to_layout.insert(tuple_kind, basic_type.clone());
928
929        basic_type
930    }
931}
932
933fn create_basic_type(
934    type_id: TypeId,
935    kind: BasicTypeKind,
936    size: MemorySize,
937    alignment: MemoryAlignment,
938) -> BasicTypeRef {
939    let basic_type_id = BasicTypeId(type_id.inner());
940
941    Rc::new(BasicType {
942        id: basic_type_id,
943        kind,
944        total_size: size,
945        max_alignment: alignment,
946    })
947}
948
949pub const fn check_type_size(ty: &BasicType, _comment: &str) {
950    if ty.total_size.0 > 1024 * 1024 {
951        //eprintln!("suspicious allocation: {} for {ty}", ty.total_size);
952    }
953}