Landin library reference source

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