ruka_codegen_wasm/memory_and_release/
pointer_ops.rs

1use super::*;
2
3pub(crate) fn emit_pointer_alloc(
4    body: &mut walrus::InstrSeqBuilder,
5    runtime: &RuntimeFunctions,
6    memory_id: MemoryId,
7    source_pos: Option<ruka_mir::MirSourcePos>,
8    fallback_line: i32,
9    src_local: LocalId,
10    src_ty: ValType,
11    dst_local: LocalId,
12) -> Result<(), LowerError> {
13    emit_heap_alloc(
14        body,
15        runtime,
16        POINTER_CELL_BYTES,
17        ALLOC_SITE_POINTER_NEW,
18        source_pos,
19        fallback_line,
20        dst_local,
21    )?;
22    body.local_get(dst_local).i32_const(1).instr(Store {
23        memory: memory_id,
24        kind: StoreKind::I32 { atomic: false },
25        arg: MemArg {
26            align: 4,
27            offset: ARRAY_HEADER_OFFSET,
28        },
29    });
30    body.local_get(dst_local).local_get(src_local);
31    emit_widen_to_i64(body, src_ty)?;
32    body.instr(Store {
33        memory: memory_id,
34        kind: StoreKind::I64 { atomic: false },
35        arg: MemArg {
36            align: 8,
37            offset: POINTER_VALUE_OFFSET,
38        },
39    });
40    Ok(())
41}
42
43pub(crate) fn emit_pointer_release(
44    body: &mut walrus::InstrSeqBuilder,
45    runtime: &RuntimeFunctions,
46    memory_id: MemoryId,
47    pointer_local: LocalId,
48    pointee_ty: &Ty,
49    structs: &[ruka_mir::MirStructDecl],
50    enums: &[ruka_mir::MirEnumDecl],
51    pointer_drop_functions: &BTreeMap<String, FunctionId>,
52    scratch_ptr_local: LocalId,
53    scratch_count_local: LocalId,
54    scratch_size_local: LocalId,
55    scratch_value_local: LocalId,
56    scratch_i64_local: LocalId,
57) -> Result<(), LowerError> {
58    let pointer_key = ty_key(&Ty::Pointer(Box::new(pointee_ty.clone())));
59    if let Some(function_id) = pointer_drop_functions.get(&pointer_key) {
60        body.local_get(pointer_local).call(*function_id);
61        return Ok(());
62    }
63    let free = runtime_function(runtime, wasm_api::RT_FREE_BYTES_SYMBOL)?;
64    let pointee_release_plan = build_release_plan(pointee_ty, structs, enums)?;
65    emit_pointer_release_with_free(
66        body,
67        memory_id,
68        pointer_local,
69        &pointee_release_plan,
70        pointer_drop_functions,
71        scratch_ptr_local,
72        scratch_count_local,
73        scratch_size_local,
74        scratch_value_local,
75        scratch_i64_local,
76        free.function_id,
77    );
78    Ok(())
79}
80
81pub(crate) fn emit_pointer_release_with_free(
82    body: &mut walrus::InstrSeqBuilder,
83    memory_id: MemoryId,
84    pointer_local: LocalId,
85    pointee_release_plan: &ReleasePlan,
86    pointer_drop_functions: &BTreeMap<String, FunctionId>,
87    scratch_ptr_local: LocalId,
88    scratch_count_local: LocalId,
89    scratch_size_local: LocalId,
90    scratch_value_local: LocalId,
91    scratch_i64_local: LocalId,
92    free_id: FunctionId,
93) {
94    let nested_value_local =
95        nested_release_value_local(pointer_local, scratch_size_local, scratch_value_local);
96    body.local_get(pointer_local)
97        .local_set(scratch_ptr_local)
98        .local_get(scratch_ptr_local)
99        .local_set(scratch_size_local)
100        .local_get(scratch_ptr_local)
101        .i32_const(0)
102        .binop(BinaryOp::I32Ne)
103        .if_else(
104            None,
105            |then_| {
106                then_
107                    .local_get(scratch_ptr_local)
108                    .instr(Load {
109                        memory: memory_id,
110                        kind: LoadKind::I32 { atomic: false },
111                        arg: MemArg {
112                            align: 4,
113                            offset: ARRAY_HEADER_OFFSET,
114                        },
115                    })
116                    .local_set(scratch_count_local)
117                    .local_get(scratch_count_local)
118                    .i32_const(1)
119                    .binop(BinaryOp::I32Eq)
120                    .if_else(
121                        None,
122                        |owned_| {
123                            owned_
124                                .local_get(scratch_ptr_local)
125                                .i32_const(0)
126                                .instr(Store {
127                                    memory: memory_id,
128                                    kind: StoreKind::I32 { atomic: false },
129                                    arg: MemArg {
130                                        align: 4,
131                                        offset: ARRAY_HEADER_OFFSET,
132                                    },
133                                });
134                            if !matches!(pointee_release_plan, ReleasePlan::None) {
135                                owned_
136                                    .local_get(scratch_ptr_local)
137                                    .instr(Load {
138                                        memory: memory_id,
139                                        kind: LoadKind::I64 { atomic: false },
140                                        arg: MemArg {
141                                            align: 8,
142                                            offset: POINTER_VALUE_OFFSET,
143                                        },
144                                    })
145                                    .local_set(scratch_i64_local)
146                                    .local_get(scratch_i64_local)
147                                    .unop(UnaryOp::I32WrapI64)
148                                    .local_set(nested_value_local);
149                                emit_release_plan_with_free(
150                                    owned_,
151                                    memory_id,
152                                    nested_value_local,
153                                    pointee_release_plan,
154                                    pointer_drop_functions,
155                                    scratch_ptr_local,
156                                    scratch_count_local,
157                                    scratch_size_local,
158                                    scratch_value_local,
159                                    scratch_i64_local,
160                                    true,
161                                    free_id,
162                                );
163                            }
164                            owned_
165                                .local_get(pointer_local)
166                                .i32_const(POINTER_CELL_BYTES)
167                                .call(free_id);
168                        },
169                        |_already_released| {},
170                    );
171            },
172            |_else_| {},
173        );
174}