1use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7use source_map_node::Node;
8use swamp_semantic::{Expression, MapType};
9use swamp_vm_isa::MemoryOffset;
10use swamp_vm_types::types::{BasicTypeRef, Place, VmType};
11use swamp_vm_types::{MemoryLocation, PointerLocation};
12
13impl CodeBuilder<'_> {
14 pub fn map_subscript_helper(
16 &mut self,
17 map_header_location: &Place,
18 map_type: &MapType,
19 key_expression: &Expression,
20 should_create_if_needed: bool,
21 ctx: &Context,
22 ) -> Place {
23 let map_header_ptr_reg = self.emit_compute_effective_address_to_register(
24 map_header_location,
25 &key_expression.node,
26 "get map header absolute pointer",
27 );
28
29 let pointer_location = PointerLocation::new(map_header_ptr_reg);
30
31 let key_temp_storage_reg =
33 self.emit_aggregate_pointer_or_pointer_to_scalar_memory(key_expression, ctx);
34
35 let gen_value_type = self.state.layout_cache.layout(&map_type.value);
36 let map_entry_reg = self.temp_registers.allocate(
37 VmType::new_unknown_placement(gen_value_type.clone()),
38 "map entry temp",
39 );
40
41 if should_create_if_needed {
42 self.builder.add_map_get_or_reserve_entry_location(
43 map_entry_reg.register(),
44 &pointer_location,
45 &key_temp_storage_reg,
46 &key_expression.node,
47 "lookup the entry for this key, or create one, in the map",
48 );
49 let map_value_pointer = MemoryLocation::new_copy_over_whole_type_with_zero_offset(
51 map_entry_reg.register.clone(),
52 );
53 self.emit_initialize_memory_for_any_type(
54 &map_value_pointer,
55 &key_expression.node,
56 "initialize the map value entry, just to be safe",
57 );
58 } else {
59 self.builder.add_map_get_entry_location(
60 map_entry_reg.register(),
61 &pointer_location,
62 &key_temp_storage_reg,
63 &key_expression.node,
64 "lookup the entry for this key in the map",
65 );
66 }
67
68 Place::Memory(MemoryLocation {
70 base_ptr_reg: map_entry_reg.register,
71 offset: MemoryOffset(0),
72 ty: VmType::new_unknown_placement(gen_value_type),
73 })
74 }
75
76 pub(crate) fn emit_map_storage_init_from_initializer_pair_list(
77 &mut self,
78 target_map_header_ptr_reg: &PointerLocation, initializer_pair_list_expressions: &[(Expression, Expression)],
80 key_type: &BasicTypeRef,
81 value_type: &BasicTypeRef,
82 logical_limit: usize,
83 node: &Node,
84 comment: &str,
85 ctx: &Context,
86 ) {
87 let hwm = self.temp_registers.save_mark();
88
89 let safe_output_register = self.temp_registers.allocate(
90 VmType::new_contained_in_register(
91 target_map_header_ptr_reg.ptr_reg.ty.basic_type().clone(),
92 ),
93 "safe output destination for map initialization list",
94 );
95 self.builder.add_mov_reg(
96 &safe_output_register.register,
97 &target_map_header_ptr_reg.ptr_reg,
98 node,
99 "safe output register destination for map initialization",
100 );
101 let safe_output_map_header_pointer_location =
102 PointerLocation::new(safe_output_register.register);
103
104 let key_frame_location = self.allocate_frame_space_and_return_destination_to_it(
105 key_type,
106 false,
107 node,
108 "key temporary storage",
109 );
110 let key_frame_place = key_frame_location
111 .vm_type()
112 .unwrap()
113 .frame_placed_type()
114 .unwrap();
115
116 let value_target_register = self.temp_registers.allocate(
117 VmType::new_unknown_placement(value_type.clone()),
118 "key temp",
119 );
120
121 for (key_expr, value_expr) in initializer_pair_list_expressions {
122 let initializer_pair_node = &key_expr.node;
123 let hwm_loop = self.temp_registers.save_mark();
124
125 if key_frame_location.ty().total_size.0 > 1 {
126 self.builder.add_frame_memory_clear(
127 key_frame_place.region(),
128 initializer_pair_node,
129 "clear key area each time, to make sure hash is calculated correctly",
130 );
131 }
132
133 self.emit_expression_into_target_memory(
134 key_frame_location.grab_memory_location(),
135 key_expr,
136 "store key to memory",
137 ctx,
138 );
139
140 self.builder.add_map_get_or_reserve_entry_location(
141 value_target_register.register(),
142 &safe_output_map_header_pointer_location,
143 &key_frame_location.grab_memory_location().base_ptr_reg,
144 initializer_pair_node,
145 "find existing or create a map entry to write into",
146 );
147
148 let value_memory_location = MemoryLocation {
149 base_ptr_reg: value_target_register.register().clone(),
150 offset: MemoryOffset(0),
151 ty: VmType::new_unknown_placement(value_type.clone()),
152 };
153
154 if value_type.is_aggregate() {
156 self.emit_initialize_memory_for_any_type(
157 &value_memory_location,
158 initializer_pair_node,
159 "initialize map entry completely",
160 );
161 }
162
163 self.emit_expression_into_target_memory(
164 &value_memory_location,
165 value_expr,
166 "put value into map entry value section",
167 ctx,
168 );
169
170 self.temp_registers.restore_to_mark(hwm_loop);
171 }
172
173 self.temp_registers.restore_to_mark(hwm);
174 }
175}