ruka_codegen_wasm/memory_and_release/
collection_ops.rs1use super::*;
2
3pub(crate) fn emit_enum_release(
4 body: &mut walrus::InstrSeqBuilder,
5 runtime: &RuntimeFunctions,
6 memory_id: MemoryId,
7 enum_local: LocalId,
8 enum_ty: &Ty,
9 structs: &[ruka_mir::MirStructDecl],
10 enums: &[ruka_mir::MirEnumDecl],
11 pointer_drop_functions: &BTreeMap<String, FunctionId>,
12 scratch_ptr_local: LocalId,
13 scratch_count_local: LocalId,
14 scratch_size_local: LocalId,
15 scratch_value_local: LocalId,
16 scratch_i64_local: LocalId,
17) -> Result<(), LowerError> {
18 let free = runtime_function(runtime, wasm_api::RT_FREE_BYTES_SYMBOL)?;
19 let enum_release_plan = build_release_plan(enum_ty, structs, enums)?;
20 body.local_get(enum_local)
21 .i32_const(0)
22 .binop(BinaryOp::I32Ne)
23 .if_else(
24 None,
25 |then_| {
26 emit_release_plan_with_free(
27 then_,
28 memory_id,
29 enum_local,
30 &enum_release_plan,
31 pointer_drop_functions,
32 scratch_ptr_local,
33 scratch_count_local,
34 scratch_size_local,
35 scratch_value_local,
36 scratch_i64_local,
37 true,
38 free.function_id,
39 );
40 },
41 |_else_| {},
42 );
43 Ok(())
44}
45
46pub(crate) fn emit_array_release(
47 body: &mut walrus::InstrSeqBuilder,
48 runtime: &RuntimeFunctions,
49 memory_id: MemoryId,
50 array_local: LocalId,
51 item_ty: &Ty,
52 structs: &[ruka_mir::MirStructDecl],
53 enums: &[ruka_mir::MirEnumDecl],
54 pointer_drop_functions: &BTreeMap<String, FunctionId>,
55 scratch_ptr_local: LocalId,
56 scratch_count_local: LocalId,
57 scratch_size_local: LocalId,
58 scratch_value_local: LocalId,
59 scratch_i64_local: LocalId,
60) -> Result<(), LowerError> {
61 let free = runtime_function(runtime, wasm_api::RT_FREE_BYTES_SYMBOL)?;
62 let item_release_plan = build_release_plan(item_ty, structs, enums)?;
63 emit_array_release_with_free(
64 body,
65 memory_id,
66 array_local,
67 &item_release_plan,
68 pointer_drop_functions,
69 scratch_ptr_local,
70 scratch_count_local,
71 scratch_size_local,
72 scratch_value_local,
73 scratch_i64_local,
74 true,
75 free.function_id,
76 );
77 Ok(())
78}
79
80pub(crate) fn emit_array_release_shallow(
81 body: &mut walrus::InstrSeqBuilder,
82 runtime: &RuntimeFunctions,
83 memory_id: MemoryId,
84 array_local: LocalId,
85 scratch_ptr_local: LocalId,
86 scratch_count_local: LocalId,
87 scratch_size_local: LocalId,
88 scratch_value_local: LocalId,
89 scratch_i64_local: LocalId,
90) -> Result<(), LowerError> {
91 let free = runtime_function(runtime, wasm_api::RT_FREE_BYTES_SYMBOL)?;
92 emit_array_release_with_free(
93 body,
94 memory_id,
95 array_local,
96 &ReleasePlan::None,
97 &BTreeMap::new(),
98 scratch_ptr_local,
99 scratch_count_local,
100 scratch_size_local,
101 scratch_value_local,
102 scratch_i64_local,
103 true,
104 free.function_id,
105 );
106 Ok(())
107}
108
109pub(crate) fn emit_array_release_with_free(
110 body: &mut walrus::InstrSeqBuilder,
111 memory_id: MemoryId,
112 array_local: LocalId,
113 item_release_plan: &ReleasePlan,
114 pointer_drop_functions: &BTreeMap<String, FunctionId>,
115 scratch_ptr_local: LocalId,
116 scratch_count_local: LocalId,
117 scratch_size_local: LocalId,
118 scratch_value_local: LocalId,
119 scratch_i64_local: LocalId,
120 free_container: bool,
121 free_id: FunctionId,
122) {
123 let nested_value_local =
124 nested_release_value_local(array_local, scratch_size_local, scratch_value_local);
125 body.local_get(array_local)
126 .i32_const(0)
127 .binop(BinaryOp::I32Ne)
128 .if_else(
129 None,
130 |then_| {
131 then_
132 .local_get(array_local)
133 .instr(Load {
134 memory: memory_id,
135 kind: LoadKind::I32 { atomic: false },
136 arg: MemArg {
137 align: 4,
138 offset: ARRAY_HEADER_OFFSET,
139 },
140 })
141 .local_set(scratch_ptr_local)
142 .local_get(scratch_ptr_local)
143 .i32_const(1)
144 .binop(BinaryOp::I32Eq)
145 .if_else(
146 None,
147 |owned_| {
148 owned_.local_get(array_local).i32_const(0).instr(Store {
149 memory: memory_id,
150 kind: StoreKind::I32 { atomic: false },
151 arg: MemArg {
152 align: 4,
153 offset: ARRAY_HEADER_OFFSET,
154 },
155 });
156 if !matches!(item_release_plan, ReleasePlan::None) {
157 owned_.block(None, |done| {
158 let done_id = done.id();
159 done.loop_(None, |loop_| {
160 let loop_id = loop_.id();
161 loop_
162 .local_get(array_local)
163 .instr(Load {
164 memory: memory_id,
165 kind: LoadKind::I32 { atomic: false },
166 arg: MemArg {
167 align: 4,
168 offset: ARRAY_LEN_OFFSET,
169 },
170 })
171 .local_set(scratch_count_local)
172 .local_get(scratch_count_local)
173 .i32_const(0)
174 .binop(BinaryOp::I32Eq)
175 .br_if(done_id)
176 .local_get(scratch_count_local)
177 .i32_const(1)
178 .binop(BinaryOp::I32Sub)
179 .local_set(scratch_count_local)
180 .local_get(array_local)
181 .local_get(scratch_count_local)
182 .instr(Store {
183 memory: memory_id,
184 kind: StoreKind::I32 { atomic: false },
185 arg: MemArg {
186 align: 4,
187 offset: ARRAY_LEN_OFFSET,
188 },
189 })
190 .local_get(array_local)
191 .i32_const(ARRAY_DATA_OFFSET as i32)
192 .binop(BinaryOp::I32Add)
193 .local_get(scratch_count_local)
194 .i32_const(ARRAY_SLOT_BYTES)
195 .binop(BinaryOp::I32Mul)
196 .binop(BinaryOp::I32Add)
197 .instr(Load {
198 memory: memory_id,
199 kind: LoadKind::I64 { atomic: false },
200 arg: MemArg {
201 align: 8,
202 offset: 0,
203 },
204 })
205 .local_set(scratch_i64_local)
206 .local_get(scratch_i64_local)
207 .unop(UnaryOp::I32WrapI64)
208 .local_set(nested_value_local);
209 emit_release_plan_with_free(
210 loop_,
211 memory_id,
212 nested_value_local,
213 item_release_plan,
214 pointer_drop_functions,
215 scratch_ptr_local,
216 scratch_count_local,
217 scratch_size_local,
218 scratch_value_local,
219 scratch_i64_local,
220 true,
221 free_id,
222 );
223 loop_.br(loop_id);
224 });
225 });
226 }
227 if free_container {
228 owned_
229 .local_get(array_local)
230 .instr(Load {
231 memory: memory_id,
232 kind: LoadKind::I32 { atomic: false },
233 arg: MemArg {
234 align: 4,
235 offset: ARRAY_CAP_OFFSET,
236 },
237 })
238 .i32_const(ARRAY_SLOT_BYTES)
239 .binop(BinaryOp::I32Mul)
240 .i32_const(ARRAY_DATA_OFFSET as i32)
241 .binop(BinaryOp::I32Add)
242 .local_set(scratch_size_local)
243 .local_get(array_local)
244 .local_get(scratch_size_local)
245 .call(free_id);
246 }
247 },
248 |_already_released| {},
249 );
250 },
251 |_else_| {},
252 );
253}