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