1use crate::{TrapCode, Vm, get_reg, i16_from_u8s, set_reg, u16_from_u8s, u32_from_u8s};
6use std::ptr;
7use swamp_vm_isa::SparseIterator;
8
9impl Vm {
10 pub fn execute_sparse_init(
11 &mut self,
12 dest_reg: u8,
13 element_size_0: u8,
14 element_size_1: u8,
15 element_size_2: u8,
16 element_size_3: u8,
17 capacity_0: u8,
18 capacity_1: u8,
19 ) {
20 let element_size = u32_from_u8s!(
21 element_size_0,
22 element_size_1,
23 element_size_2,
24 element_size_3
25 );
26 let capacity = u16_from_u8s!(capacity_0, capacity_1);
27
28 unsafe {
29 let dest_addr = get_reg!(self, dest_reg);
30 let sparse_ptr = self.memory.get_heap_ptr(dest_addr as usize);
31 sparse_mem::init(sparse_ptr, capacity, element_size);
32 }
33 }
34
35 pub fn execute_sparse_add_get_entry_addr(
36 &mut self,
37 dest_entry_addr_reg: u8,
38 dest_handle_reg: u8,
39 sparse_ptr_reg: u8,
40 memory_size_0: u8,
41 memory_size_1: u8,
42 memory_size_2: u8,
43 memory_size_3: u8,
44 ) {
45 let element_size =
46 u32_from_u8s!(memory_size_0, memory_size_1, memory_size_2, memory_size_3);
47
48 unsafe {
49 let sparse_addr = get_reg!(self, sparse_ptr_reg);
50 let sparse_ptr = self.memory.get_heap_ptr(sparse_addr as usize);
51 if let Some((index, generation)) = sparse_mem::allocate(sparse_ptr) {
52 let relative_sparse_addr_offset = sparse_mem::values_offset(sparse_ptr);
53 let addr_for_values_start = sparse_addr as usize + relative_sparse_addr_offset;
54 let element_addr = addr_for_values_start + index as usize * element_size as usize;
55
56 let handle = (index as u32) << 16 | (generation as u32);
57 if self.debug_operations_enabled {
58 eprintln!("sparse_add: handle: {handle} 0x{handle:X} ({index}:{generation})");
59 }
60 set_reg!(self, dest_handle_reg, handle);
61 set_reg!(self, dest_entry_addr_reg, element_addr as u32);
62 } else {
63 self.internal_trap(TrapCode::SparseOutOfSpace);
64 }
65 }
66 }
67
68 pub fn execute_sparse_get_entry_addr(
69 &mut self,
70 dest_entry_addr_reg: u8,
71 sparse_ptr_reg: u8,
72 int_handle_reg: u8,
73 memory_size_lower: u8,
74 memory_size_upper: u8,
75 ) {
76 let element_size = u16_from_u8s!(memory_size_lower, memory_size_upper);
77 let handle = get_reg!(self, int_handle_reg);
78
79 let index = handle >> 16;
80 let generation = handle & 0xffff;
81
82 unsafe {
83 let sparse_addr = get_reg!(self, sparse_ptr_reg);
84 let sparse_ptr = self.memory.get_heap_ptr(sparse_addr as usize);
85 if sparse_mem::is_alive(sparse_ptr, index as u16, generation as u16) {
86 let relative_sparse_addr_offset = sparse_mem::values_offset(sparse_ptr);
87 let addr_for_values_start = sparse_addr as usize + relative_sparse_addr_offset;
88 let element_addr = addr_for_values_start + index as usize * element_size as usize;
89 set_reg!(self, dest_entry_addr_reg, element_addr);
90
91 if self.debug_operations_enabled {
92 eprintln!("sparse_get: handle: {handle} 0x{handle:X} ({index}:{generation})");
93 }
94 } else {
95 self.internal_trap(TrapCode::SparseGetFailed)
96 }
97 }
98 }
99
100 pub fn execute_sparse_remove(&mut self, sparse_ptr_reg: u8, int_handle_reg: u8) {
101 unsafe {
102 let sparse_addr = get_reg!(self, sparse_ptr_reg);
103 let sparse_ptr = self.memory.get_heap_ptr(sparse_addr as usize);
104 let handle = get_reg!(self, int_handle_reg);
105 let index = handle >> 16;
106 let generation = handle & 0xffff;
107 let could_be_removed = sparse_mem::remove(sparse_ptr, index as u16, generation as u16);
108 if !could_be_removed {
109 self.internal_trap(TrapCode::SparseRemoveFailed);
110 }
111 if self.debug_operations_enabled {
112 eprintln!("sparse_remove: handle: {handle} 0x{handle:X} ({index}:{generation})");
113 }
114 }
115 }
116
117 pub fn execute_sparse_is_alive(
118 &mut self,
119 dest_reg_bool: u8,
120 sparse_ptr_reg: u8,
121 int_handle_reg: u8,
122 ) {
123 unsafe {
124 let sparse_addr = get_reg!(self, sparse_ptr_reg);
125 let sparse_ptr = self.memory.get_heap_ptr(sparse_addr as usize);
126 let handle = get_reg!(self, int_handle_reg);
127 let index = handle >> 16;
128 let generation = handle & 0xffff;
129 let is_alive = sparse_mem::is_alive(sparse_ptr, index as u16, generation as u16);
130 set_reg!(self, dest_reg_bool, is_alive);
131 if self.debug_operations_enabled {
132 eprintln!("sparse_is_alive: handle: {handle} 0x{handle:X} ({index}:{generation})");
133 }
134 }
135 }
136
137 pub(crate) fn execute_sparse_iter_init(
138 &mut self,
139 target_map_iterator_header_reg: u8,
140 map_header_reg: u8,
141 ) {
142 let sparse_header_addr = get_reg!(self, map_header_reg);
143
144 #[cfg(feature = "debug_vm")]
145 self.debug_operations_enabled;
146 let map_iterator = SparseIterator {
147 sparse_header_heap_ptr: sparse_header_addr,
148 index: 0,
149 };
150
151 let map_iterator_mut_ptr =
152 self.get_ptr_from_reg(target_map_iterator_header_reg) as *mut SparseIterator;
153
154 unsafe {
155 ptr::write(map_iterator_mut_ptr, map_iterator);
156 }
157 }
158
159 pub fn get_sparse_iterator_header_ptr_from_reg(
160 &self,
161 map_iterator_reg: u8,
162 ) -> *mut SparseIterator {
163 self.get_ptr_from_reg(map_iterator_reg) as *mut SparseIterator
164 }
165
166 pub fn execute_sparse_iter_next_pair(
167 &mut self,
168 sparse_iterator_header_reg: u8,
169 target_key_reg: u8,
170 target_value_reg: u8,
171 branch_offset_lower: u8,
172 branch_offset_upper: u8,
173 ) {
174 let sparse_iterator =
175 self.get_sparse_iterator_header_ptr_from_reg(sparse_iterator_header_reg);
176
177 unsafe {
178 let sparse_header_addr = (*sparse_iterator).sparse_header_heap_ptr;
179 let sparse_header_ptr = self.memory.get_heap_const_ptr(sparse_header_addr as usize);
180
181 let element_count = sparse_mem::element_count(sparse_header_ptr);
182 let current_index = (*sparse_iterator).index as usize;
183 if (current_index as u32) < element_count as u32 {
184 let values_index = (*sparse_mem::slot_to_id_ptr_const(sparse_header_ptr)
185 .add(current_index)) as usize;
186
187 #[cfg(feature = "debug_vm")]
188 if self.debug_operations_enabled {
189 eprintln!("index {current_index}, slot: {values_index}");
190 }
191
192 let offset_to_values = sparse_mem::values_offset(sparse_header_ptr);
193 let values_start = sparse_header_addr as usize + offset_to_values;
194
195 let element_size = sparse_mem::element_size(sparse_header_ptr) as usize;
196 let entry_addr = values_start + values_index * element_size;
197
198 let generation =
199 *sparse_mem::generation_ptr_const(sparse_header_ptr).add(values_index);
200 let handle = (values_index as u32) << 16 | (generation as u32);
201 set_reg!(self, target_key_reg, handle);
202 set_reg!(self, target_value_reg, entry_addr);
203 (*sparse_iterator).index += 1;
204 } else {
205 let branch_offset = i16_from_u8s!(branch_offset_lower, branch_offset_upper);
207
208 #[cfg(feature = "debug_vm")]
209 if self.debug_operations_enabled {
210 eprintln!("iteration done, jumping {branch_offset}");
211 }
212 self.pc = (self.pc as i32 + branch_offset as i32) as usize;
213 }
214 }
215 }
216
217 pub fn execute_sparse_iter_next(
218 &mut self,
219 sparse_iterator_header_reg: u8,
220 target_entry_address_reg: u8,
221 branch_offset_lower: u8,
222 branch_offset_upper: u8,
223 ) {
224 let sparse_iterator =
225 self.get_sparse_iterator_header_ptr_from_reg(sparse_iterator_header_reg);
226
227 unsafe {
228 let sparse_header_addr = (*sparse_iterator).sparse_header_heap_ptr;
229 let sparse_header_ptr = self.memory.get_heap_const_ptr(sparse_header_addr as usize);
230
231 let element_count = sparse_mem::element_count(sparse_header_ptr);
232 let current_index = (*sparse_iterator).index as usize;
233 if (current_index as u32) < element_count as u32 {
234 let values_index = (*sparse_mem::slot_to_id_ptr_const(sparse_header_ptr)
235 .add(current_index)) as usize;
236
237 #[cfg(feature = "debug_vm")]
238 if self.debug_operations_enabled {
239 eprintln!("index {current_index}, slot: {values_index}");
240 }
241
242 let offset_to_values = sparse_mem::values_offset(sparse_header_ptr);
243 let values_start = sparse_header_addr as usize + offset_to_values;
244
245 let element_size = sparse_mem::element_size(sparse_header_ptr) as usize;
246 let entry_addr = values_start + values_index * element_size;
247
248 set_reg!(self, target_entry_address_reg, entry_addr);
249 (*sparse_iterator).index += 1;
250 } else {
251 let branch_offset = i16_from_u8s!(branch_offset_lower, branch_offset_upper);
253
254 #[cfg(feature = "debug_vm")]
255 if self.debug_operations_enabled {
256 eprintln!("iteration done, jumping {branch_offset}");
257 }
258 self.pc = (self.pc as i32 + branch_offset as i32) as usize;
259 }
260 }
261 }
262}