ruka_codegen_wasm/memory_and_release/
collection_ops.rs

1use 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}