ruka_codegen_wasm/memory_and_release/
pointer_ops.rs1use 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}