compiler/tests/fixtures/runtime/hosted-heap-provider/main.ldn
1import hosted/heap
2import core/mem
3import core/vec
4
5no_allocation: atom
6allocation: type = no_allocation | ptr mut u8
7same_block: (saved: allocation, block: ptr mut u8) -> (same: bool) =
8 match saved
9 no_allocation: same = false
10 ptr (present): same = usize(present) == usize(block)
11 end match
12end same_block
13
14is_absent: (value: allocation) -> (empty: bool) =
15 match value
16 no_allocation: empty = true
17 ptr: empty = false
18 end match
19end is_absent
20
21-- This fixture-local provider is an observer, not the reusable failure
22-- wrapper `core/failing` supplies. It delegates every operation
23-- to the real heap while retaining the two simultaneously live extents.
24audit: type = struct
25 inner: heap.system
26 first_live: bool
27 first_block: allocation
28 first_size: usize
29 second_live: bool
30 second_block: allocation
31 second_size: usize
32 live: usize
33 peak_live: usize
34 allocations: usize
35 frees: usize
36 first_alloc_size: usize
37 second_alloc_size: usize
38 first_free_size: usize
39 second_free_size: usize
40 coexistence: bool
41 mismatch: bool
42end audit
43
44new_audit: () -> (state: audit) =
45 state = (inner: heap.host(),
46 first_live: false, first_block: no_allocation, first_size: 0,
47 second_live: false, second_block: no_allocation, second_size: 0,
48 live: 0, peak_live: 0, allocations: 0, frees: 0,
49 first_alloc_size: 0, second_alloc_size: 0,
50 first_free_size: 0, second_free_size: 0,
51 coexistence: false, mismatch: false)
52end new_audit
53
54audit_alloc: (inout state: audit, size: usize, alignment: usize)
55 -> (block: ptr mut u8) ! mem.out_of_memory =
56 block = try mem.allocate(state.inner, size, alignment)
57 if state.first_live and state.second_live then
58 mem.free(state.inner, block, size)
59 fail mem.out_of_memory
60 end if
61
62 if state.live > 0 then
63 state.coexistence = true
64 end if
65 inc state.live
66 if state.live > state.peak_live then
67 state.peak_live = state.live
68 end if
69 inc state.allocations
70 if state.allocations == 1 then
71 state.first_alloc_size = size
72 elsif state.allocations == 2 then
73 state.second_alloc_size = size
74 end if
75 if alignment > 1 and usize(block) % alignment <> 0 then
76 state.mismatch = true
77 end if
78
79 if not state.first_live then
80 state.first_live = true
81 state.first_block = block
82 state.first_size = size
83 else
84 state.second_live = true
85 state.second_block = block
86 state.second_size = size
87 end if
88end audit_alloc
89
90audit_free: (inout state: audit, block: ptr mut u8, size: usize) -> none =
91 mut matched: bool = false
92 if state.first_live and same_block(state.first_block, block) then
93 if size <> state.first_size then
94 state.mismatch = true
95 end if
96 state.first_live = false
97 state.first_block = no_allocation
98 matched = true
99 elsif state.second_live and same_block(state.second_block, block) then
100 if size <> state.second_size then
101 state.mismatch = true
102 end if
103 state.second_live = false
104 state.second_block = no_allocation
105 matched = true
106 end if
107 if not matched then
108 state.mismatch = true
109 else
110 dec state.live
111 end if
112
113 inc state.frees
114 if state.frees == 1 then
115 state.first_free_size = size
116 elsif state.frees == 2 then
117 state.second_free_size = size
118 end if
119 mem.free(state.inner, block, size)
120end audit_free
121
122audit_grow: (inout state: audit, block: ptr mut u8,
123 old_size: usize, new_size: usize, alignment: usize)
124 -> (grown: bool) =
125 _ = state.live
126 _ = block
127 _ = old_size
128 _ = new_size
129 _ = alignment
130 grown = false
131end audit_grow
132
133audit is mem.allocator (alloc: audit_alloc, grow: audit_grow,
134 free: audit_free)
135
136node: type = struct
137 value: i32
138end node
139
140node_1: node = (value: 1)
141node_2: node = (value: 2)
142node_3: node = (value: 3)
143node_4: node = (value: 4)
144node_5: node = (value: 5)
145node_6: node = (value: 6)
146node_7: node = (value: 7)
147node_8: node = (value: 8)
148node_9: node = (value: 9)
149
150public main: () -> (code: i32) =
151 code = 1
152 mut observed := new_audit()
153 mut trace: i32 = 0
154
155 maximum: usize = 18446744073709551615
156 one: usize = 1
157 mut refused: bool = false
158 impossible: allocation = mem.allocate(observed, maximum, one)
159 else (problem)
160 _ = problem
161 refused = true
162 no_allocation
163 end
164 if refused and is_absent(impossible) and observed.allocations == 0 then
165 trace = trace + 1
166 end if
167
168 first_size: usize = 17
169 first_alignment: usize = 24
170 second_size: usize = 31
171 second_alignment: usize = 64
172 first: ptr mut u8 = mem.allocate
173 (observed, first_size, first_alignment) else (problem)
174 _ = problem
175 return
176 end
177 second: ptr mut u8 = mem.allocate
178 (observed, second_size, second_alignment) else (problem)
179 _ = problem
180 return
181 end
182
183 first_last: ptr mut u8 = ptr(usize(first) + first_size - 1)
184 second_last: ptr mut u8 = ptr(usize(second) + second_size - 1)
185 first.val = 11
186 first_last.val = 17
187 second.val = 23
188 second_last.val = 31
189 if usize(first) <> 0 and usize(second) <> 0
190 and usize(first) <> usize(second)
191 and usize(first) % first_alignment == 0
192 and usize(second) % second_alignment == 0
193 and first.val == 11 and first_last.val == 17
194 and second.val == 23 and second_last.val == 31
195 and observed.live == 2 and observed.peak_live == 2
196 and observed.coexistence and not observed.mismatch
197 then
198 trace = trace + 2
199 end if
200 mem.free(observed, first, first_size)
201 mem.free(observed, second, second_size)
202
203 empty_size: usize = 0
204 empty_alignment: usize = 0
205 empty: ptr mut u8 = mem.allocate
206 (observed, empty_size, empty_alignment) else (problem)
207 _ = problem
208 return
209 end
210 another_empty: ptr mut u8 = mem.allocate
211 (observed, empty_size, one) else (problem)
212 _ = problem
213 return
214 end
215 if usize(empty) <> 0 and usize(another_empty) <> 0
216 and usize(empty) <> usize(another_empty) and observed.live == 2
217 then
218 trace = trace + 4
219 end if
220 mem.free(observed, empty, empty_size)
221 mem.free(observed, another_empty, empty_size)
222 if observed.live == 0 and observed.allocations == 4
223 and observed.frees == 4 and not observed.first_live
224 and not observed.second_live and not observed.mismatch
225 and is_absent(observed.first_block)
226 and is_absent(observed.second_block)
227 then
228 trace = trace + 8
229 end if
230
231 mut growth := new_audit()
232 mut values := vec.new(item: ptr node)
233 vec.push(values, growth, addr node_1) else 0
234 vec.push(values, growth, addr node_2) else 0
235 vec.push(values, growth, addr node_3) else 0
236 vec.push(values, growth, addr node_4) else 0
237 vec.push(values, growth, addr node_5) else 0
238 vec.push(values, growth, addr node_6) else 0
239 vec.push(values, growth, addr node_7) else 0
240 vec.push(values, growth, addr node_8) else 0
241 vec.push(values, growth, addr node_9) else 0
242
243 at_first: usize = 0
244 at_eighth: usize = 7
245 at_ninth: usize = 8
246 kept_first: ptr node = vec.get(values, at_first) else addr node_9
247 kept_eighth: ptr node = vec.get(values, at_eighth) else addr node_9
248 kept_ninth: ptr node = vec.get(values, at_ninth) else addr node_1
249 if kept_first.val.value == 1 and kept_eighth.val.value == 8
250 and kept_ninth.val.value == 9 and vec.length(values) == 9
251 and vec.capacity(values) == 16 and growth.allocations == 2
252 and growth.frees == 1 and growth.live == 1
253 and growth.peak_live == 2 and growth.coexistence
254 and growth.first_alloc_size == 8 * sizeof ptr node
255 and growth.second_alloc_size == 16 * sizeof ptr node
256 and growth.first_free_size == 8 * sizeof ptr node
257 and not growth.mismatch
258 then
259 trace = trace + 16
260 end if
261 vec.release(values, growth)
262
263 if vec.length(values) == 0 and vec.capacity(values) == 0
264 and growth.allocations == 2 and growth.frees == 2
265 and growth.live == 0 and not growth.first_live
266 and not growth.second_live
267 and is_absent(growth.first_block) and is_absent(growth.second_block)
268 and growth.second_free_size == 16 * sizeof ptr node
269 and not growth.mismatch
270 then
271 trace = trace + 32
272 end if
273
274 if trace == 63 then
275 code = 42
276 else
277 code = trace
278 end if
279end main