swamp_code_gen/
init.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 */
5use crate::code_bld::CodeBuilder;
6use source_map_node::Node;
7use swamp_vm_types::types::{BasicTypeKind, BasicTypeRef, VmType, u16_type, u32_type};
8use swamp_vm_types::{AggregateMemoryLocation, CountU16, MemoryLocation};
9
10impl CodeBuilder<'_> {
11    /// Helper function to initialize collections in any type (struct, tuple, optional, etc.)
12    pub(crate) fn emit_initialize_collections_in_type(
13        &mut self,
14        location: &AggregateMemoryLocation,
15        type_ref: &BasicTypeRef,
16        node: &Node,
17        comment: &str,
18    ) {
19        match &type_ref.kind {
20            // Direct collection types that need initialization
21            // TODO: Should be in a helper
22            BasicTypeKind::MapStorage { .. }
23            | BasicTypeKind::StringStorage { .. }
24            | BasicTypeKind::VecStorage(..)
25            | BasicTypeKind::GridStorage(..)
26            | BasicTypeKind::SparseStorage(..)
27            | BasicTypeKind::StackStorage(..)
28            | BasicTypeKind::QueueStorage(..)
29            | BasicTypeKind::FixedCapacityArray(..) => {
30                // Initialize the collection
31                self.emit_initialize_collection_metadata(
32                    &location.location,
33                    node,
34                    &format!("{comment} - emit_initialize_collections_in_type"),
35                );
36            }
37
38            // Container types that might contain collections
39            BasicTypeKind::Struct(_) => {
40                self.initialize_struct_collection_fields(location, type_ref, node, comment);
41            }
42
43            BasicTypeKind::Tuple(tuple_info) => {
44                for (i, tuple_field) in tuple_info.fields.iter().enumerate() {
45                    let tuple_field_location =
46                        location.offset(tuple_field.offset, tuple_field.ty.clone());
47                    self.emit_initialize_collections_in_type(
48                        &tuple_field_location,
49                        &tuple_field.ty,
50                        node,
51                        &format!("{comment} - emit_initialize_collections_in_type tuple field {i}"),
52                    );
53                }
54            }
55
56            // For tagged unions (including Optional types)
57            BasicTypeKind::TaggedUnion(union_info) => {
58                // We can't initialize collections inside unions at struct creation time
59                // because we don't know which variant will be active
60            }
61
62            _ => {}
63        }
64    }
65
66    /// Helper function to recursively initialize collection fields in a struct
67    fn initialize_struct_collection_fields(
68        &mut self,
69        struct_location: &AggregateMemoryLocation,
70        struct_type: &BasicTypeRef,
71        node: &Node,
72        comment: &str,
73    ) {
74        match &struct_type.kind {
75            BasicTypeKind::Struct(struct_info) => {
76                // Iterate through all fields in the struct
77                for field in &struct_info.fields {
78                    // Calculate the field's memory location
79                    let field_location = struct_location.offset(field.offset, field.ty.clone());
80
81                    // Recursively initialize any collections in this field
82                    self.emit_initialize_collections_in_type(
83                        &field_location,
84                        &field.ty,
85                        node,
86                        &format!("{comment} - field {}", field.name),
87                    );
88                }
89            }
90            // Handle other container types that might contain collections
91            BasicTypeKind::Tuple(tuple_info) => {
92                for (i, tuple_field) in tuple_info.fields.iter().enumerate() {
93                    let tuple_field_location =
94                        struct_location.offset(tuple_field.offset, tuple_field.ty.clone());
95                    self.emit_initialize_collections_in_type(
96                        &tuple_field_location,
97                        &tuple_field.ty,
98                        node,
99                        &format!("{comment} - tuple field {i}"),
100                    );
101                }
102            }
103            BasicTypeKind::TaggedUnion(union_info) => {
104                // For tagged unions (including Optional types), we can't initialize collections
105                // since we don't know which variant is active yet
106            }
107            _ => {}
108        }
109    }
110
111    /// Initialize memory for any type that might contain collections
112    ///
113    /// This is the main public interface for memory initialization. It handles:
114    /// - Direct collections: Initializes the collection metadata (capacity, etc.)
115    /// - Container types: Recursively initializes any collections they contain
116    /// - Scalar types: Does nothing (no initialization needed)
117    ///
118    /// Use this function whenever you need to ensure that memory is properly initialized
119    /// for any type that might contain collections, either directly or nested.
120    pub fn emit_initialize_memory_for_any_type(
121        &mut self,
122        memory_location: &MemoryLocation,
123        node: &Node,
124        comment: &str,
125    ) {
126        let basic_type = memory_location.ty.basic_type();
127
128        // Handle direct collections
129        if basic_type.is_collection() {
130            self.emit_initialize_collection_metadata(memory_location, node, comment);
131            return;
132        }
133
134        // Handle container types that might contain collections
135        let aggregate_location = AggregateMemoryLocation {
136            location: memory_location.clone(),
137        };
138
139        self.emit_initialize_collections_in_type(&aggregate_location, basic_type, node, comment);
140    }
141
142    /// Initialize memory for a collection type at the specified location
143    ///
144    /// This function is responsible for initializing the metadata for collection types:
145    /// - For collections (Vec, Map, etc.), it sets the capacity field based on the type definition
146    /// - Does NOT handle nested collections - use `emit_initialize_collections_in_type` for that
147    ///
148    /// This is a specialized function for direct collection initialization only.
149    pub fn emit_initialize_collection_metadata(
150        &mut self,
151        memory_location: &MemoryLocation,
152        node: &Node,
153        comment: &str,
154    ) {
155        let basic_type = memory_location.ty.basic_type();
156        if !basic_type.is_collection() {
157            return; // Not a collection, nothing to initialize
158        }
159
160        match &basic_type.kind {
161            BasicTypeKind::FixedCapacityArray(element_type, capacity) => {
162                let absolute_pointer = self
163                    .emit_compute_effective_address_from_location_to_register(
164                        memory_location,
165                        node,
166                        &format!("{comment} - compute address for vec init when pointer_location() is None"),
167                    );
168
169                self.builder
170                    .add_fixed_capacity_array_init_fill_capacity_and_len(
171                        &absolute_pointer,
172                        *capacity as u16,
173                        &element_type.total_size,
174                        node,
175                        &format!("{comment} - initialize fixed capacity array init"),
176                    );
177            }
178            BasicTypeKind::SparseStorage(element_type, capacity) => {
179                let absolute_pointer = self
180                    .emit_compute_effective_address_from_location_to_register(
181                        memory_location,
182                        node,
183                        &format!("{comment} - load effective address for sparse"),
184                    );
185                self.builder.add_sparse_init(
186                    &absolute_pointer,
187                    element_type.total_size,
188                    *capacity as u16,
189                    node,
190                    comment,
191                );
192            }
193            BasicTypeKind::GridStorage(element_type, width, height) => {
194                let hwm = self.temp_registers.save_mark();
195
196                let absolute_pointer = self
197                    .emit_compute_effective_address_from_location_to_register(
198                        memory_location,
199                        node,
200                        "compute address for grid init when pointer_location() is None",
201                    );
202
203                let init_element_size = self.temp_registers.allocate(
204                    VmType::new_contained_in_register(u16_type()),
205                    &format!("{comment} - init grid init_element_size"),
206                );
207
208                self.builder.add_mov_32_immediate_value(
209                    init_element_size.register(),
210                    element_type.total_size.0,
211                    node,
212                    &format!("{comment} -set grid element size {memory_location}"),
213                );
214
215                self.builder.add_grid_init(
216                    &absolute_pointer.ptr_reg,
217                    &init_element_size.register,
218                    *width as u16,
219                    *height as u16,
220                    node,
221                    comment,
222                );
223
224                self.temp_registers.restore_to_mark(hwm);
225            }
226            BasicTypeKind::MapStorage {
227                logical_limit,
228                key_type,
229                value_type,
230                ..
231            } => {
232                let hwm = self.temp_registers.save_mark();
233
234                let unaligned_key_size = key_type.total_size;
235                let key_alignment = key_type.max_alignment;
236                let unaligned_value_size = value_type.total_size;
237                let value_alignment = value_type.max_alignment;
238
239                let init_key_size = self.temp_registers.allocate(
240                    VmType::new_contained_in_register(u32_type()),
241                    &format!("{comment} - init map key_size reg"),
242                );
243                self.builder.add_mov_32_immediate_value(
244                    init_key_size.register(),
245                    unaligned_key_size.0,
246                    node,
247                    &format!("{comment} -set init key_size value to {memory_location}"),
248                );
249
250                let init_value_size = self.temp_registers.allocate(
251                    VmType::new_contained_in_register(u32_type()),
252                    &format!("{comment} - init map value_size reg"),
253                );
254                self.builder.add_mov_32_immediate_value(
255                    init_value_size.register(),
256                    unaligned_value_size.0,
257                    node,
258                    &format!("{comment} -set init value_size value to {memory_location}"),
259                );
260
261                let map_pointer_location = self
262                    .emit_compute_effective_address_from_location_to_register(
263                        memory_location,
264                        node,
265                        "find location of map to init",
266                    );
267
268                self.builder.add_map_init_set_capacity(
269                    &map_pointer_location,
270                    CountU16(*logical_limit as u16),
271                    init_key_size.register(),
272                    key_alignment,
273                    init_value_size.register(),
274                    value_alignment,
275                    node,
276                    &format!(
277                        "{comment} - initialize map (capacity, key_size, total_key_and_value_size)"
278                    ),
279                );
280
281                self.temp_registers.restore_to_mark(hwm);
282            }
283            BasicTypeKind::VecStorage(element_type, capacity)
284            | BasicTypeKind::StackStorage(element_type, capacity)
285            | BasicTypeKind::StringStorage {
286                element_type,
287                capacity,
288                ..
289            }
290            | BasicTypeKind::QueueStorage(element_type, capacity) => {
291                let absolute_pointer = self
292                    .emit_compute_effective_address_from_location_to_register(
293                        memory_location,
294                        node,
295                        "compute address for vec init when pointer_location() is None",
296                    );
297                self.builder.add_vec_init_set_capacity(
298                    &absolute_pointer,
299                    CountU16(*capacity as u16),
300                    &element_type.total_size,
301                    node,
302                    "initialize vec like (vec, stack, queue)",
303                );
304            }
305
306            _ => {}
307        }
308    }
309}