GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/heap.c
Date: 2024-11-05 17:11:09
Exec Total Coverage
Lines: 687 826 83.2%
Functions: 70 84 83.3%
Branches: 246 351 70.1%

Line Branch Exec Source
1 /*
2 Copyright 2018, 2020, 2022 - 2024 Joel Svensson svenssonjoel@yahoo.se
3 2022 Benjamin Vedder
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <stdarg.h>
23 #include <inttypes.h>
24 #include <lbm_memory.h>
25 #include <lbm_custom_type.h>
26 #include <lbm_defrag_mem.h>
27
28 #include "heap.h"
29 #include "symrepr.h"
30 #include "stack.h"
31 #include "lbm_channel.h"
32 #include "platform_mutex.h"
33 #include "eval_cps.h"
34 #ifdef VISUALIZE_HEAP
35 #include "heap_vis.h"
36 #endif
37
38
39 33790884 static inline lbm_value lbm_set_gc_mark(lbm_value x) {
40 33790884 return x | LBM_GC_MARKED;
41 }
42
43 33624654 static inline lbm_value lbm_clr_gc_mark(lbm_value x) {
44 33624654 return x & ~LBM_GC_MASK;
45 }
46
47 804335870 static inline bool lbm_get_gc_mark(lbm_value x) {
48 804335870 return x & LBM_GC_MASK;
49 }
50
51 // flag is the same bit as mark, but in car
52 static inline bool lbm_get_gc_flag(lbm_value x) {
53 return x & LBM_GC_MARKED;
54 }
55
56 static inline lbm_value lbm_set_gc_flag(lbm_value x) {
57 return x | LBM_GC_MARKED;
58 }
59
60 static inline lbm_value lbm_clr_gc_flag(lbm_value x) {
61 return x & ~LBM_GC_MASK;
62 }
63
64
65 lbm_heap_state_t lbm_heap_state;
66
67 lbm_const_heap_t *lbm_const_heap_state;
68
69 lbm_cons_t *lbm_heaps[2] = {NULL, NULL};
70
71 static mutex_t lbm_const_heap_mutex;
72 static bool lbm_const_heap_mutex_initialized = false;
73
74 static mutex_t lbm_mark_mutex;
75 static bool lbm_mark_mutex_initialized = false;
76
77 #ifdef USE_GC_PTR_REV
78 void lbm_gc_lock(void) {
79 mutex_lock(&lbm_mark_mutex);
80 }
81 void lbm_gc_unlock(void) {
82 mutex_unlock(&lbm_mark_mutex);
83 }
84 #else
85 void lbm_gc_lock(void) {
86 }
87 void lbm_gc_unlock(void) {
88 }
89 #endif
90
91 /****************************************************/
92 /* ENCODERS DECODERS */
93
94 2849162 lbm_value lbm_enc_i32(int32_t x) {
95 #ifndef LBM64
96 2849162 lbm_value i = lbm_cons((lbm_uint)x, ENC_SYM_RAW_I_TYPE);
97
2/2
✓ Branch 1 taken 9674 times.
✓ Branch 2 taken 2839488 times.
2849162 if (lbm_type_of(i) == LBM_TYPE_SYMBOL) return i;
98 2839488 return lbm_set_ptr_type(i, LBM_TYPE_I32);
99 #else
100 return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_I32;
101 #endif
102 }
103
104 3682448 lbm_value lbm_enc_u32(uint32_t x) {
105 #ifndef LBM64
106 3682448 lbm_value u = lbm_cons(x, ENC_SYM_RAW_U_TYPE);
107
2/2
✓ Branch 1 taken 2828 times.
✓ Branch 2 taken 3679620 times.
3682448 if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u;
108 3679620 return lbm_set_ptr_type(u, LBM_TYPE_U32);
109 #else
110 return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_U32;
111 #endif
112 }
113
114 22374 lbm_value lbm_enc_float(float x) {
115 #ifndef LBM64
116 lbm_uint t;
117 22374 memcpy(&t, &x, sizeof(lbm_float));
118 22374 lbm_value f = lbm_cons(t, ENC_SYM_RAW_F_TYPE);
119
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22374 times.
22374 if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f;
120 22374 return lbm_set_ptr_type(f, LBM_TYPE_FLOAT);
121 #else
122 lbm_uint t = 0;
123 memcpy(&t, &x, sizeof(float));
124 return (((lbm_uint)t) << LBM_VAL_SHIFT) | LBM_TYPE_FLOAT;
125 #endif
126 }
127
128 #ifndef LBM64
129 8434134 static lbm_value enc_64_on_32(uint8_t *source, lbm_uint type_qual, lbm_uint type) {
130 8434134 lbm_value res = lbm_cons(ENC_SYM_NIL,ENC_SYM_NIL);
131
2/2
✓ Branch 1 taken 8431812 times.
✓ Branch 2 taken 2322 times.
8434134 if (lbm_type_of(res) != LBM_TYPE_SYMBOL) {
132 8431812 uint8_t* storage = lbm_malloc(sizeof(uint64_t));
133
2/2
✓ Branch 0 taken 8429104 times.
✓ Branch 1 taken 2708 times.
8431812 if (storage) {
134 8429104 memcpy(storage,source, sizeof(uint64_t));
135 8429104 lbm_set_car_and_cdr(res, (lbm_uint)storage, type_qual);
136 8429104 res = lbm_set_ptr_type(res, type);
137 } else {
138 2708 res = ENC_SYM_MERROR;
139 }
140 }
141 8434134 return res;
142 }
143 #endif
144
145 4495172 lbm_value lbm_enc_i64(int64_t x) {
146 #ifndef LBM64
147 4495172 return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_I_TYPE, LBM_TYPE_I64);
148 #else
149 lbm_value u = lbm_cons((uint64_t)x, ENC_SYM_RAW_I_TYPE);
150 if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u;
151 return lbm_set_ptr_type(u, LBM_TYPE_I64);
152 #endif
153 }
154
155 3372994 lbm_value lbm_enc_u64(uint64_t x) {
156 #ifndef LBM64
157 3372994 return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_U_TYPE, LBM_TYPE_U64);
158 #else
159 lbm_value u = lbm_cons(x, ENC_SYM_RAW_U_TYPE);
160 if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u;
161 return lbm_set_ptr_type(u, LBM_TYPE_U64);
162 #endif
163 }
164
165 565968 lbm_value lbm_enc_double(double x) {
166 #ifndef LBM64
167 565968 return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_F_TYPE, LBM_TYPE_DOUBLE);
168 #else
169 lbm_uint t;
170 memcpy(&t, &x, sizeof(double));
171 lbm_value f = lbm_cons(t, ENC_SYM_RAW_F_TYPE);
172 if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f;
173 return lbm_set_ptr_type(f, LBM_TYPE_DOUBLE);
174 #endif
175 }
176
177 // Type specific (as opposed to the dec_as_X) functions
178 // should only be run on values KNOWN to represent a value of the type
179 // that the decoder decodes.
180
181 33297 float lbm_dec_float(lbm_value x) {
182 #ifndef LBM64
183 float f_tmp;
184 33297 lbm_uint tmp = lbm_car(x);
185 33297 memcpy(&f_tmp, &tmp, sizeof(float));
186 33297 return f_tmp;
187 #else
188 uint32_t tmp = (uint32_t)(x >> LBM_VAL_SHIFT);
189 float f_tmp;
190 memcpy(&f_tmp, &tmp, sizeof(float));
191 return f_tmp;
192 #endif
193 }
194
195 564764 double lbm_dec_double(lbm_value x) {
196 #ifndef LBM64
197 double d;
198 564764 uint32_t *data = (uint32_t*)lbm_car(x);
199 564764 memcpy(&d, data, sizeof(double));
200 564764 return d;
201 #else
202 double f_tmp;
203 lbm_uint tmp = lbm_car(x);
204 memcpy(&f_tmp, &tmp, sizeof(double));
205 return f_tmp;
206 #endif
207 }
208
209 7017326 uint64_t lbm_dec_u64(lbm_value x) {
210 #ifndef LBM64
211 uint64_t u;
212 7017326 uint32_t *data = (uint32_t*)lbm_car(x);
213 7017326 memcpy(&u, data, 8);
214 7017326 return u;
215 #else
216 return (uint64_t)lbm_car(x);
217 #endif
218 }
219
220 9259084 int64_t lbm_dec_i64(lbm_value x) {
221 #ifndef LBM64
222 int64_t i;
223 9259084 uint32_t *data = (uint32_t*)lbm_car(x);
224 9259084 memcpy(&i, data, 8);
225 9259084 return i;
226 #else
227 return (int64_t)lbm_car(x);
228 #endif
229 }
230
231 486818 char *lbm_dec_str(lbm_value val) {
232 486818 char *res = 0;
233 // If val is an array, car of val will be non-null.
234
2/2
✓ Branch 1 taken 486622 times.
✓ Branch 2 taken 196 times.
486818 if (lbm_is_array_r(val)) {
235 486622 lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(val);
236 486622 res = (char *)array->data;
237 }
238 486818 return res;
239 }
240
241 11022993 lbm_char_channel_t *lbm_dec_channel(lbm_value val) {
242 11022993 lbm_char_channel_t *res = NULL;
243
244
1/2
✓ Branch 1 taken 11022993 times.
✗ Branch 2 not taken.
11022993 if (lbm_type_of(val) == LBM_TYPE_CHANNEL) {
245 11022993 res = (lbm_char_channel_t *)lbm_car(val);
246 }
247 11022993 return res;
248 }
249
250 980 lbm_uint lbm_dec_custom(lbm_value val) {
251 980 lbm_uint res = 0;
252
1/2
✓ Branch 1 taken 980 times.
✗ Branch 2 not taken.
980 if (lbm_type_of(val) == LBM_TYPE_CUSTOM) {
253 980 res = (lbm_uint)lbm_car(val);
254 }
255 980 return res;
256 }
257
258 60872 uint8_t lbm_dec_as_char(lbm_value a) {
259 60872 uint8_t r = 0;
260
9/10
✓ Branch 1 taken 60648 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 28 times.
✓ Branch 8 taken 28 times.
✓ Branch 9 taken 28 times.
✗ Branch 10 not taken.
60872 switch (lbm_type_of_functional(a)) {
261 60648 case LBM_TYPE_CHAR:
262 60648 r = (uint8_t)lbm_dec_char(a); break;
263 28 case LBM_TYPE_I:
264 28 r = (uint8_t)lbm_dec_i(a); break;
265 28 case LBM_TYPE_U:
266 28 r = (uint8_t)lbm_dec_u(a); break;
267 28 case LBM_TYPE_I32:
268 28 r = (uint8_t)lbm_dec_i32(a); break;
269 28 case LBM_TYPE_U32:
270 28 r = (uint8_t)lbm_dec_u32(a); break;
271 28 case LBM_TYPE_FLOAT:
272 28 r = (uint8_t)lbm_dec_float(a); break;
273 28 case LBM_TYPE_I64:
274 28 r = (uint8_t)lbm_dec_i64(a); break;
275 28 case LBM_TYPE_U64:
276 28 r = (uint8_t)lbm_dec_u64(a); break;
277 28 case LBM_TYPE_DOUBLE:
278 28 r = (uint8_t) lbm_dec_double(a); break;
279 }
280 60872 return r;
281 }
282
283 8421300 uint32_t lbm_dec_as_u32(lbm_value a) {
284 8421300 uint32_t r = 0;
285
9/9
✓ Branch 1 taken 561938 times.
✓ Branch 2 taken 1275660 times.
✓ Branch 3 taken 1786468 times.
✓ Branch 4 taken 4795104 times.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 84 times.
✓ Branch 8 taken 28 times.
✓ Branch 9 taken 1962 times.
8421300 switch (lbm_type_of_functional(a)) {
286 561938 case LBM_TYPE_CHAR:
287 561938 r = (uint32_t)lbm_dec_char(a); break;
288 1275660 case LBM_TYPE_I:
289 1275660 r = (uint32_t)lbm_dec_i(a); break;
290 1786468 case LBM_TYPE_U:
291 1786468 r = (uint32_t)lbm_dec_u(a); break;
292 4795104 case LBM_TYPE_I32: /* fall through */
293 case LBM_TYPE_U32:
294 4795104 r = (uint32_t)lbm_dec_u32(a); break;
295 28 case LBM_TYPE_FLOAT:
296 28 r = (uint32_t)lbm_dec_float(a); break;
297 28 case LBM_TYPE_I64:
298 28 r = (uint32_t)lbm_dec_i64(a); break;
299 84 case LBM_TYPE_U64:
300 84 r = (uint32_t)lbm_dec_u64(a); break;
301 28 case LBM_TYPE_DOUBLE:
302 28 r = (uint32_t)lbm_dec_double(a); break;
303 }
304 8421300 return r;
305 }
306
307 206212995 int32_t lbm_dec_as_i32(lbm_value a) {
308 206212995 int32_t r = 0;
309
10/10
✓ Branch 1 taken 5809792 times.
✓ Branch 2 taken 196720419 times.
✓ Branch 3 taken 196 times.
✓ Branch 4 taken 3674140 times.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 56 times.
✓ Branch 8 taken 56 times.
✓ Branch 9 taken 28 times.
✓ Branch 10 taken 8252 times.
206212995 switch (lbm_type_of_functional(a)) {
310 5809792 case LBM_TYPE_CHAR:
311 5809792 r = (int32_t)lbm_dec_char(a); break;
312 196720419 case LBM_TYPE_I:
313 196720419 r = (int32_t)lbm_dec_i(a); break;
314 196 case LBM_TYPE_U:
315 196 r = (int32_t)lbm_dec_u(a); break;
316 3674140 case LBM_TYPE_I32:
317 3674140 r = (int32_t)lbm_dec_i32(a); break;
318 28 case LBM_TYPE_U32:
319 28 r = (int32_t)lbm_dec_u32(a); break;
320 28 case LBM_TYPE_FLOAT:
321 28 r = (int32_t)lbm_dec_float(a); break;
322 56 case LBM_TYPE_I64:
323 56 r = (int32_t)lbm_dec_i64(a); break;
324 56 case LBM_TYPE_U64:
325 56 r = (int32_t)lbm_dec_u64(a); break;
326 28 case LBM_TYPE_DOUBLE:
327 28 r = (int32_t) lbm_dec_double(a); break;
328 }
329 206212995 return r;
330 }
331
332 6732120 int64_t lbm_dec_as_i64(lbm_value a) {
333 6732120 int64_t r = 0;
334
9/10
✓ Branch 1 taken 562266 times.
✓ Branch 2 taken 1402750 times.
✓ Branch 3 taken 168 times.
✓ Branch 4 taken 168 times.
✓ Branch 5 taken 168 times.
✓ Branch 6 taken 56 times.
✓ Branch 7 taken 4766376 times.
✓ Branch 8 taken 112 times.
✓ Branch 9 taken 56 times.
✗ Branch 10 not taken.
6732120 switch (lbm_type_of_functional(a)) {
335 562266 case LBM_TYPE_CHAR:
336 562266 r = (int64_t)lbm_dec_char(a); break;
337 1402750 case LBM_TYPE_I:
338 1402750 r = (int64_t)lbm_dec_i(a); break;
339 168 case LBM_TYPE_U:
340 168 r = (int64_t)lbm_dec_u(a); break;
341 168 case LBM_TYPE_I32:
342 168 r = (int64_t)lbm_dec_i32(a); break;
343 168 case LBM_TYPE_U32:
344 168 r = (int64_t)lbm_dec_u32(a); break;
345 56 case LBM_TYPE_FLOAT:
346 56 r = (int64_t)lbm_dec_float(a); break;
347 4766376 case LBM_TYPE_I64:
348 4766376 r = (int64_t)lbm_dec_i64(a); break;
349 112 case LBM_TYPE_U64:
350 112 r = (int64_t)lbm_dec_u64(a); break;
351 56 case LBM_TYPE_DOUBLE:
352 56 r = (int64_t) lbm_dec_double(a); break;
353 }
354 6732120 return r;
355 }
356
357 4490278 uint64_t lbm_dec_as_u64(lbm_value a) {
358 4490278 uint64_t r = 0;
359
9/10
✓ Branch 1 taken 562238 times.
✓ Branch 2 taken 280852 times.
✓ Branch 3 taken 168 times.
✓ Branch 4 taken 168 times.
✓ Branch 5 taken 168 times.
✓ Branch 6 taken 56 times.
✓ Branch 7 taken 168 times.
✓ Branch 8 taken 3646404 times.
✓ Branch 9 taken 56 times.
✗ Branch 10 not taken.
4490278 switch (lbm_type_of_functional(a)) {
360 562238 case LBM_TYPE_CHAR:
361 562238 r = (uint64_t)lbm_dec_char(a); break;
362 280852 case LBM_TYPE_I:
363 280852 r = (uint64_t)lbm_dec_i(a); break;
364 168 case LBM_TYPE_U:
365 168 r = (uint64_t)lbm_dec_u(a); break;
366 168 case LBM_TYPE_I32:
367 168 r = (uint64_t)lbm_dec_i32(a); break;
368 168 case LBM_TYPE_U32:
369 168 r = (uint64_t)lbm_dec_u32(a); break;
370 56 case LBM_TYPE_FLOAT:
371 56 r = (uint64_t)lbm_dec_float(a); break;
372 168 case LBM_TYPE_I64:
373 168 r = (uint64_t)lbm_dec_i64(a); break;
374 3646404 case LBM_TYPE_U64:
375 3646404 r = (uint64_t)lbm_dec_u64(a); break;
376 56 case LBM_TYPE_DOUBLE:
377 56 r = (uint64_t)lbm_dec_double(a); break;
378 }
379 4490278 return r;
380 }
381
382 2324 lbm_uint lbm_dec_as_uint(lbm_value a) {
383 2324 lbm_uint r = 0;
384
1/10
✗ Branch 1 not taken.
✓ Branch 2 taken 2324 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2324 switch (lbm_type_of_functional(a)) {
385 case LBM_TYPE_CHAR:
386 r = (lbm_uint)lbm_dec_char(a); break;
387 2324 case LBM_TYPE_I:
388 2324 r = (lbm_uint)lbm_dec_i(a); break;
389 case LBM_TYPE_U:
390 r = (lbm_uint)lbm_dec_u(a); break;
391 case LBM_TYPE_I32:
392 r = (lbm_uint)lbm_dec_i32(a); break;
393 case LBM_TYPE_U32:
394 r = (lbm_uint)lbm_dec_u32(a); break;
395 case LBM_TYPE_FLOAT:
396 r = (lbm_uint)lbm_dec_float(a); break;
397 case LBM_TYPE_I64:
398 r = (lbm_uint)lbm_dec_i64(a); break;
399 case LBM_TYPE_U64:
400 r = (lbm_uint) lbm_dec_u64(a); break;
401 case LBM_TYPE_DOUBLE:
402 r = (lbm_uint)lbm_dec_double(a); break;
403 }
404 2324 return r;
405 }
406
407 644 lbm_int lbm_dec_as_int(lbm_value a) {
408 644 lbm_int r = 0;
409
1/10
✗ Branch 1 not taken.
✓ Branch 2 taken 644 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
644 switch (lbm_type_of_functional(a)) {
410 case LBM_TYPE_CHAR:
411 r = (lbm_int)lbm_dec_char(a); break;
412 644 case LBM_TYPE_I:
413 644 r = (lbm_int)lbm_dec_i(a); break;
414 case LBM_TYPE_U:
415 r = (lbm_int)lbm_dec_u(a); break;
416 case LBM_TYPE_I32:
417 r = (lbm_int)lbm_dec_i32(a); break;
418 case LBM_TYPE_U32:
419 r = (lbm_int)lbm_dec_u32(a); break;
420 case LBM_TYPE_FLOAT:
421 r = (lbm_int)lbm_dec_float(a); break;
422 case LBM_TYPE_I64:
423 r = (lbm_int)lbm_dec_i64(a); break;
424 case LBM_TYPE_U64:
425 r = (lbm_int)lbm_dec_u64(a); break;
426 case LBM_TYPE_DOUBLE:
427 r = (lbm_int)lbm_dec_double(a); break;
428 }
429 644 return r;
430 }
431
432 19493 float lbm_dec_as_float(lbm_value a) {
433 19493 float r = 0;
434
9/10
✓ Branch 1 taken 1176 times.
✓ Branch 2 taken 2128 times.
✓ Branch 3 taken 140 times.
✓ Branch 4 taken 140 times.
✓ Branch 5 taken 196 times.
✓ Branch 6 taken 15405 times.
✓ Branch 7 taken 140 times.
✓ Branch 8 taken 140 times.
✓ Branch 9 taken 28 times.
✗ Branch 10 not taken.
19493 switch (lbm_type_of_functional(a)) {
435 1176 case LBM_TYPE_CHAR:
436 1176 r = (float)lbm_dec_char(a); break;
437 2128 case LBM_TYPE_I:
438 2128 r = (float)lbm_dec_i(a); break;
439 140 case LBM_TYPE_U:
440 140 r = (float)lbm_dec_u(a); break;
441 140 case LBM_TYPE_I32:
442 140 r = (float)lbm_dec_i32(a); break;
443 196 case LBM_TYPE_U32:
444 196 r = (float)lbm_dec_u32(a); break;
445 15405 case LBM_TYPE_FLOAT:
446 15405 r = (float)lbm_dec_float(a); break;
447 140 case LBM_TYPE_I64:
448 140 r = (float)lbm_dec_i64(a); break;
449 140 case LBM_TYPE_U64:
450 140 r = (float)lbm_dec_u64(a); break;
451 28 case LBM_TYPE_DOUBLE:
452 28 r = (float)lbm_dec_double(a); break;
453 }
454 19493 return r;
455 }
456
457 564204 double lbm_dec_as_double(lbm_value a) {
458 564204 double r = 0;
459
9/10
✓ Branch 1 taken 281168 times.
✓ Branch 2 taken 280880 times.
✓ Branch 3 taken 140 times.
✓ Branch 4 taken 140 times.
✓ Branch 5 taken 140 times.
✓ Branch 6 taken 364 times.
✓ Branch 7 taken 140 times.
✓ Branch 8 taken 140 times.
✓ Branch 9 taken 1092 times.
✗ Branch 10 not taken.
564204 switch (lbm_type_of_functional(a)) {
460 281168 case LBM_TYPE_CHAR:
461 281168 r = (double)lbm_dec_char(a); break;
462 280880 case LBM_TYPE_I:
463 280880 r = (double)lbm_dec_i(a); break;
464 140 case LBM_TYPE_U:
465 140 r = (double)lbm_dec_u(a); break;
466 140 case LBM_TYPE_I32:
467 140 r = (double)lbm_dec_i32(a); break;
468 140 case LBM_TYPE_U32:
469 140 r = (double)lbm_dec_u32(a); break;
470 364 case LBM_TYPE_FLOAT:
471 364 r = (double)lbm_dec_float(a); break;
472 140 case LBM_TYPE_I64:
473 140 r = (double)lbm_dec_i64(a); break;
474 140 case LBM_TYPE_U64:
475 140 r = (double)lbm_dec_u64(a); break;
476 1092 case LBM_TYPE_DOUBLE:
477 1092 r = (double)lbm_dec_double(a); break;
478 }
479 564204 return r;
480 }
481
482 /****************************************************/
483 /* HEAP MANAGEMENT */
484
485 21504 static int generate_freelist(size_t num_cells) {
486 21504 size_t i = 0;
487
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21504 times.
21504 if (!lbm_heap_state.heap) return 0;
489
490 21504 lbm_heap_state.freelist = lbm_enc_cons_ptr(0);
491
492 lbm_cons_t *t;
493
494 // Add all cells to free list
495
2/2
✓ Branch 0 taken 199732224 times.
✓ Branch 1 taken 21504 times.
199753728 for (i = 1; i < num_cells; i ++) {
496 199732224 t = lbm_ref_cell(lbm_enc_cons_ptr(i-1));
497 199732224 t->car = ENC_SYM_RECOVERED; // all cars in free list are "RECOVERED"
498 199732224 t->cdr = lbm_enc_cons_ptr(i);
499 }
500
501 // Replace the incorrect pointer at the last cell.
502 21504 t = lbm_ref_cell(lbm_enc_cons_ptr(num_cells-1));
503 21504 t->cdr = ENC_SYM_NIL;
504
505 21504 return 1;
506 }
507
508 347628 void lbm_nil_freelist(void) {
509 347628 lbm_heap_state.freelist = ENC_SYM_NIL;
510 347628 lbm_heap_state.num_alloc = lbm_heap_state.heap_size;
511 347628 }
512
513 21504 static void heap_init_state(lbm_cons_t *addr, lbm_uint num_cells,
514 lbm_uint* gc_stack_storage, lbm_uint gc_stack_size) {
515 21504 lbm_heap_state.heap = addr;
516 21504 lbm_heap_state.heap_bytes = (unsigned int)(num_cells * sizeof(lbm_cons_t));
517 21504 lbm_heap_state.heap_size = num_cells;
518
519 21504 lbm_stack_create(&lbm_heap_state.gc_stack, gc_stack_storage, gc_stack_size);
520
521 21504 lbm_heap_state.num_alloc = 0;
522 21504 lbm_heap_state.num_alloc_arrays = 0;
523 21504 lbm_heap_state.gc_num = 0;
524 21504 lbm_heap_state.gc_marked = 0;
525 21504 lbm_heap_state.gc_recovered = 0;
526 21504 lbm_heap_state.gc_recovered_arrays = 0;
527 21504 lbm_heap_state.gc_least_free = num_cells;
528 21504 lbm_heap_state.gc_last_free = num_cells;
529 21504 }
530
531 347628 void lbm_heap_new_freelist_length(void) {
532 347628 lbm_uint l = lbm_heap_state.heap_size - lbm_heap_state.num_alloc;
533 347628 lbm_heap_state.gc_last_free = l;
534
2/2
✓ Branch 0 taken 3832 times.
✓ Branch 1 taken 343796 times.
347628 if (l < lbm_heap_state.gc_least_free)
535 3832 lbm_heap_state.gc_least_free = l;
536 347628 }
537
538 21504 int lbm_heap_init(lbm_cons_t *addr, lbm_uint num_cells,
539 lbm_uint gc_stack_size) {
540
541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21504 times.
21504 if (((uintptr_t)addr % 8) != 0) return 0;
542
543 21504 memset(addr,0, sizeof(lbm_cons_t) * num_cells);
544
545 21504 lbm_uint *gc_stack_storage = (lbm_uint*)lbm_malloc(gc_stack_size * sizeof(lbm_uint));
546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21504 times.
21504 if (gc_stack_storage == NULL) return 0;
547
548 21504 heap_init_state(addr, num_cells,
549 gc_stack_storage, gc_stack_size);
550
551 21504 lbm_heaps[0] = addr;
552
553 21504 return generate_freelist(num_cells);
554 }
555
556
557 365086859 lbm_value lbm_heap_allocate_cell(lbm_type ptr_type, lbm_value car, lbm_value cdr) {
558 lbm_value r;
559 365086859 lbm_value cell = lbm_heap_state.freelist;
560
2/2
✓ Branch 0 taken 365036367 times.
✓ Branch 1 taken 50492 times.
365086859 if (cell) {
561 365036367 lbm_uint heap_ix = lbm_dec_ptr(cell);
562 365036367 lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr;
563 365036367 lbm_heap_state.num_alloc++;
564 365036367 lbm_heap_state.heap[heap_ix].car = car;
565 365036367 lbm_heap_state.heap[heap_ix].cdr = cdr;
566 365036367 r = lbm_set_ptr_type(cell, ptr_type);
567 } else {
568 50492 r = ENC_SYM_MERROR;
569 }
570 365086859 return r;
571 }
572
573 1254704 lbm_value lbm_heap_allocate_list(lbm_uint n) {
574
2/2
✓ Branch 0 taken 3304 times.
✓ Branch 1 taken 1251400 times.
1254704 if (n == 0) return ENC_SYM_NIL;
575
2/2
✓ Branch 1 taken 1264 times.
✓ Branch 2 taken 1250136 times.
1251400 if (lbm_heap_num_free() < n) return ENC_SYM_MERROR;
576
577 1250136 lbm_value curr = lbm_heap_state.freelist;
578 1250136 lbm_value res = curr;
579
1/2
✓ Branch 1 taken 1250136 times.
✗ Branch 2 not taken.
1250136 if (lbm_type_of(curr) == LBM_TYPE_CONS) {
580
581 1250136 lbm_cons_t *c_cell = NULL;
582 1250136 lbm_uint count = 0;
583 do {
584 6465268 c_cell = lbm_ref_cell(curr);
585 6465268 c_cell->car = ENC_SYM_NIL;
586 6465268 curr = c_cell->cdr;
587 6465268 count ++;
588
2/2
✓ Branch 0 taken 5215132 times.
✓ Branch 1 taken 1250136 times.
6465268 } while (count < n);
589 1250136 lbm_heap_state.freelist = curr;
590 1250136 c_cell->cdr = ENC_SYM_NIL;
591 1250136 lbm_heap_state.num_alloc+=count;
592 1250136 return res;
593 }
594 return ENC_SYM_FATAL_ERROR;
595 }
596
597 623822 lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) {
598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 623822 times.
623822 if (n == 0) return ENC_SYM_NIL;
599
2/2
✓ Branch 1 taken 4210 times.
✓ Branch 2 taken 619612 times.
623822 if (lbm_heap_num_free() < n) return ENC_SYM_MERROR;
600
601 619612 lbm_value curr = lbm_heap_state.freelist;
602 619612 lbm_value res = curr;
603
1/2
✓ Branch 1 taken 619612 times.
✗ Branch 2 not taken.
619612 if (lbm_type_of(curr) == LBM_TYPE_CONS) {
604
605 619612 lbm_cons_t *c_cell = NULL;
606 619612 unsigned int count = 0;
607 do {
608 1523480 c_cell = lbm_ref_cell(curr);
609 1523480 c_cell->car = va_arg(valist, lbm_value);
610 1523480 curr = c_cell->cdr;
611 1523480 count ++;
612
2/2
✓ Branch 0 taken 903868 times.
✓ Branch 1 taken 619612 times.
1523480 } while (count < n);
613 619612 lbm_heap_state.freelist = curr;
614 619612 c_cell->cdr = ENC_SYM_NIL;
615 619612 lbm_heap_state.num_alloc+=count;
616 619612 return res;
617 }
618 return ENC_SYM_FATAL_ERROR;
619 }
620
621 622030 lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) {
622 va_list valist;
623 622030 va_start(valist, n);
624 622030 lbm_value r = lbm_heap_allocate_list_init_va(n, valist);
625 622030 va_end(valist);
626 622030 return r;
627 }
628
629 lbm_uint lbm_heap_num_allocated(void) {
630 return lbm_heap_state.num_alloc;
631 }
632 lbm_uint lbm_heap_size(void) {
633 return lbm_heap_state.heap_size;
634 }
635
636 lbm_uint lbm_heap_size_bytes(void) {
637 return lbm_heap_state.heap_bytes;
638 }
639
640 252 void lbm_get_heap_state(lbm_heap_state_t *res) {
641 252 *res = lbm_heap_state;
642 252 }
643
644 lbm_uint lbm_get_gc_stack_max(void) {
645 return lbm_get_max_stack(&lbm_heap_state.gc_stack);
646 }
647
648 lbm_uint lbm_get_gc_stack_size(void) {
649 return lbm_heap_state.gc_stack.size;
650 }
651
652 #ifdef USE_GC_PTR_REV
653 static inline void value_assign(lbm_value *a, lbm_value b) {
654 lbm_value a_old = *a & LBM_GC_MASK;
655 *a = a_old | (b & ~LBM_GC_MASK);
656 }
657
658 void lbm_gc_mark_phase(lbm_value root) {
659 bool work_to_do = true;
660
661 if (!lbm_is_ptr(root)) return;
662
663 mutex_lock(&lbm_const_heap_mutex);
664 lbm_value curr = root;
665 lbm_value prev = lbm_enc_cons_ptr(LBM_PTR_NULL);
666
667 while (work_to_do) {
668 // follow leftwards pointers
669 while (lbm_is_ptr(curr) &&
670 (lbm_dec_ptr(curr) != LBM_PTR_NULL) &&
671 ((curr & LBM_PTR_TO_CONSTANT_BIT) == 0) &&
672 !lbm_get_gc_mark(lbm_cdr(curr))) {
673 // Mark the cell if not a constant cell
674 lbm_cons_t *cell = lbm_ref_cell(curr);
675 cell->cdr = lbm_set_gc_mark(cell->cdr);
676 if (lbm_is_cons_rw(curr)) {
677 lbm_value next = 0;
678 value_assign(&next, cell->car);
679 value_assign(&cell->car, prev);
680 value_assign(&prev,curr);
681 value_assign(&curr, next);
682 }
683 // Will jump out next iteration as gc mark is set in curr.
684 }
685 while (lbm_is_ptr(prev) &&
686 (lbm_dec_ptr(prev) != LBM_PTR_NULL) &&
687 lbm_get_gc_flag(lbm_car(prev)) ) {
688 // clear the flag
689 lbm_cons_t *cell = lbm_ref_cell(prev);
690 cell->car = lbm_clr_gc_flag(cell->car);
691 lbm_value next = 0;
692 value_assign(&next, cell->cdr);
693 value_assign(&cell->cdr, curr);
694 value_assign(&curr, prev);
695 value_assign(&prev, next);
696 }
697 if (lbm_is_ptr(prev) &&
698 lbm_dec_ptr(prev) == LBM_PTR_NULL) {
699 work_to_do = false;
700 } else if (lbm_is_ptr(prev)) {
701 // set the flag
702 lbm_cons_t *cell = lbm_ref_cell(prev);
703 cell->car = lbm_set_gc_flag(cell->car);
704 lbm_value next = 0;
705 value_assign(&next, cell->car);
706 value_assign(&cell->car, curr);
707 value_assign(&curr, cell->cdr);
708 value_assign(&cell->cdr, next);
709 }
710 }
711 mutex_unlock(&lbm_const_heap_mutex);
712 }
713
714 #else
715 extern eval_context_t *ctx_running;
716 4810672 void lbm_gc_mark_phase(lbm_value root) {
717 lbm_value t_ptr;
718 4810672 lbm_stack_t *s = &lbm_heap_state.gc_stack;
719 4810672 s->data[s->sp++] = root;
720
721
2/2
✓ Branch 1 taken 23507304 times.
✓ Branch 2 taken 4810672 times.
28317976 while (!lbm_stack_is_empty(s)) {
722 lbm_value curr;
723 23507304 lbm_pop(s, &curr);
724
725 53591842 mark_shortcut:
726
727
2/2
✓ Branch 1 taken 32501602 times.
✓ Branch 2 taken 21090240 times.
53591842 if (!lbm_is_ptr(curr) ||
728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32501602 times.
32501602 (curr & LBM_PTR_TO_CONSTANT_BIT)) {
729 23047786 continue;
730 }
731
732 32501602 lbm_cons_t *cell = &lbm_heap_state.heap[lbm_dec_ptr(curr)];
733
734
2/2
✓ Branch 1 taken 1940914 times.
✓ Branch 2 taken 30560688 times.
32501602 if (lbm_get_gc_mark(cell->cdr)) {
735 1940914 continue;
736 }
737
738 30560688 t_ptr = lbm_type_of(curr);
739
740 // An array is marked in O(N) time using an additional 32bit
741 // value per array that keeps track of how far into the array GC
742 // has progressed.
743
2/2
✓ Branch 0 taken 18172 times.
✓ Branch 1 taken 30542516 times.
30560688 if (t_ptr == LBM_TYPE_LISPARRAY) {
744 18172 lbm_push(s, curr); // put array back as bookkeeping.
745 18172 lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car;
746 18172 lbm_value *arrdata = (lbm_value *)arr->data;
747 18172 uint32_t index = arr->index;
748
749 // Potential optimization.
750 // 1. CONS pointers are set to curr and recurse.
751 // 2. Any other ptr is marked immediately and index is increased.
752
3/4
✓ Branch 1 taken 9212 times.
✓ Branch 2 taken 8960 times.
✓ Branch 3 taken 9212 times.
✗ Branch 4 not taken.
18172 if (lbm_is_ptr(arrdata[index]) && ((arrdata[index] & LBM_PTR_TO_CONSTANT_BIT) == 0) &&
753
2/2
✓ Branch 0 taken 4508 times.
✓ Branch 1 taken 4704 times.
9212 !((arrdata[index] & LBM_CONTINUATION_INTERNAL) == LBM_CONTINUATION_INTERNAL)) {
754 4508 lbm_cons_t *elt = &lbm_heap_state.heap[lbm_dec_ptr(arrdata[index])];
755
2/2
✓ Branch 1 taken 1540 times.
✓ Branch 2 taken 2968 times.
4508 if (!lbm_get_gc_mark(elt->cdr)) {
756 1540 curr = arrdata[index];
757 1540 goto mark_shortcut;
758 }
759 }
760
2/2
✓ Branch 0 taken 15764 times.
✓ Branch 1 taken 868 times.
16632 if (index < ((arr->size/(sizeof(lbm_value))) - 1)) {
761 15764 arr->index++;
762 15764 continue;
763 }
764
765 868 arr->index = 0;
766 868 cell->cdr = lbm_set_gc_mark(cell->cdr);
767 868 lbm_heap_state.gc_marked ++;
768 868 lbm_pop(s, &curr); // Remove array from GC stack as we are done marking it.
769 868 continue;
770
2/2
✓ Branch 0 taken 175028 times.
✓ Branch 1 taken 30367488 times.
30542516 } else if (t_ptr == LBM_TYPE_CHANNEL) {
771 175028 cell->cdr = lbm_set_gc_mark(cell->cdr);
772 175028 lbm_heap_state.gc_marked ++;
773 // TODO: Can channels be explicitly freed ?
774
1/2
✓ Branch 0 taken 175028 times.
✗ Branch 1 not taken.
175028 if (cell->car != ENC_SYM_NIL) {
775 175028 lbm_char_channel_t *chan = (lbm_char_channel_t *)cell->car;
776 175028 curr = chan->dependency;
777 175028 goto mark_shortcut;
778 }
779 continue;
780 }
781
782 30367488 cell->cdr = lbm_set_gc_mark(cell->cdr);
783 30367488 lbm_heap_state.gc_marked ++;
784
785
2/2
✓ Branch 0 taken 29907970 times.
✓ Branch 1 taken 459518 times.
30367488 if (t_ptr == LBM_TYPE_CONS) {
786
2/2
✓ Branch 1 taken 18679328 times.
✓ Branch 2 taken 11228642 times.
29907970 if (lbm_is_ptr(cell->cdr)) {
787
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18679328 times.
18679328 if (!lbm_push(s, cell->cdr)) {
788 lbm_critical_error();
789 break;
790 }
791 }
792 29907970 curr = cell->car;
793 29907970 goto mark_shortcut; // Skip a push/pop
794 }
795 }
796 4810672 }
797 #endif
798
799 //Environments are proper lists with a 2 element list stored in each car.
800 11484882 void lbm_gc_mark_env(lbm_value env) {
801 11484882 lbm_value curr = env;
802 lbm_cons_t *c;
803
804
2/2
✓ Branch 1 taken 1623750 times.
✓ Branch 2 taken 11484882 times.
13108632 while (lbm_is_ptr(curr)) {
805 1623750 c = lbm_ref_cell(curr);
806 1623750 c->cdr = lbm_set_gc_mark(c->cdr); // mark the environent list structure.
807 1623750 lbm_cons_t *b = lbm_ref_cell(c->car);
808 1623750 b->cdr = lbm_set_gc_mark(b->cdr); // mark the binding list head cell.
809 1623750 lbm_gc_mark_phase(b->cdr); // mark the bound object.
810 1623750 lbm_heap_state.gc_marked +=2;
811 1623750 curr = c->cdr;
812 }
813 11484882 }
814
815
816 360786 void lbm_gc_mark_aux(lbm_uint *aux_data, lbm_uint aux_size) {
817
2/2
✓ Branch 0 taken 6120280 times.
✓ Branch 1 taken 360786 times.
6481066 for (lbm_uint i = 0; i < aux_size; i ++) {
818
2/2
✓ Branch 1 taken 3701928 times.
✓ Branch 2 taken 2418352 times.
6120280 if (lbm_is_ptr(aux_data[i])) {
819 3701928 lbm_type pt_t = lbm_type_of(aux_data[i]);
820 3701928 lbm_uint pt_v = lbm_dec_ptr(aux_data[i]);
821
3/4
✓ Branch 0 taken 3701928 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1823800 times.
✓ Branch 3 taken 1878128 times.
3701928 if( pt_t >= LBM_POINTER_TYPE_FIRST &&
822 1823800 pt_t <= LBM_POINTER_TYPE_LAST &&
823
1/2
✓ Branch 0 taken 1823800 times.
✗ Branch 1 not taken.
1823800 pt_v < lbm_heap_state.heap_size) {
824 1823800 lbm_gc_mark_phase(aux_data[i]);
825 }
826 }
827 }
828 360786 }
829
830 722736 void lbm_gc_mark_roots(lbm_uint *roots, lbm_uint num_roots) {
831
2/2
✓ Branch 0 taken 1087322 times.
✓ Branch 1 taken 722736 times.
1810058 for (lbm_uint i = 0; i < num_roots; i ++) {
832 1087322 lbm_gc_mark_phase(roots[i]);
833 }
834 722736 }
835
836 // Sweep moves non-marked heap objects to the free list.
837 347628 int lbm_gc_sweep_phase(void) {
838 347628 unsigned int i = 0;
839 347628 lbm_cons_t *heap = (lbm_cons_t *)lbm_heap_state.heap;
840
841
2/2
✓ Branch 0 taken 771829760 times.
✓ Branch 1 taken 347628 times.
772177388 for (i = 0; i < lbm_heap_state.heap_size; i ++) {
842
2/2
✓ Branch 1 taken 33624654 times.
✓ Branch 2 taken 738205106 times.
771829760 if ( lbm_get_gc_mark(heap[i].cdr)) {
843 33624654 heap[i].cdr = lbm_clr_gc_mark(heap[i].cdr);
844 } else {
845 // Check if this cell is a pointer to an array
846 // and free it.
847
2/2
✓ Branch 1 taken 686026328 times.
✓ Branch 2 taken 52178778 times.
738205106 if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL) {
848
6/7
✓ Branch 0 taken 8369376 times.
✓ Branch 1 taken 1036 times.
✓ Branch 2 taken 294678 times.
✓ Branch 3 taken 303677 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 43209983 times.
52178778 switch(heap[i].cdr) {
849
850 8369376 case ENC_SYM_IND_I_TYPE: /* fall through */
851 case ENC_SYM_IND_U_TYPE:
852 case ENC_SYM_IND_F_TYPE:
853 8369376 lbm_memory_free((lbm_uint*)heap[i].car);
854 8369376 break;
855 1036 case ENC_SYM_DEFRAG_ARRAY_TYPE:
856 1036 lbm_defrag_mem_free((lbm_uint*)heap[i].car);
857 1036 break;
858 294678 case ENC_SYM_LISPARRAY_TYPE: /* fall through */
859 case ENC_SYM_ARRAY_TYPE:{
860 294678 lbm_array_header_t *arr = (lbm_array_header_t*)heap[i].car;
861 294678 lbm_memory_free((lbm_uint *)arr->data);
862 294678 lbm_heap_state.gc_recovered_arrays++;
863 294678 lbm_memory_free((lbm_uint *)arr);
864 294678 } break;
865 303677 case ENC_SYM_CHANNEL_TYPE:{
866 303677 lbm_char_channel_t *chan = (lbm_char_channel_t*)heap[i].car;
867 303677 lbm_memory_free((lbm_uint*)chan->state);
868 303677 lbm_memory_free((lbm_uint*)chan);
869 303677 } break;
870 case ENC_SYM_CUSTOM_TYPE: {
871 lbm_uint *t = (lbm_uint*)heap[i].car;
872 lbm_custom_type_destroy(t);
873 lbm_memory_free(t);
874 } break;
875 28 case ENC_SYM_DEFRAG_MEM_TYPE: {
876 28 lbm_uint *ptr = (lbm_uint *)heap[i].car;
877 28 lbm_defrag_mem_destroy(ptr);
878 28 } break;
879 43209983 default:
880 43209983 break;
881 }
882 686026328 }
883 // create pointer to use as new freelist
884 738205106 lbm_uint addr = lbm_enc_cons_ptr(i);
885
886 // Clear the "freed" cell.
887 738205106 heap[i].car = ENC_SYM_RECOVERED;
888 738205106 heap[i].cdr = lbm_heap_state.freelist;
889 738205106 lbm_heap_state.freelist = addr;
890 738205106 lbm_heap_state.num_alloc --;
891 738205106 lbm_heap_state.gc_recovered ++;
892 }
893 }
894 347628 return 1;
895 }
896
897 347628 void lbm_gc_state_inc(void) {
898 347628 lbm_heap_state.gc_num ++;
899 347628 lbm_heap_state.gc_recovered = 0;
900 347628 lbm_heap_state.gc_marked = 0;
901 347628 }
902
903 // construct, alter and break apart
904 364428359 lbm_value lbm_cons(lbm_value car, lbm_value cdr) {
905 364428359 return lbm_heap_allocate_cell(LBM_TYPE_CONS, car, cdr);
906 }
907
908 244984198 lbm_value lbm_car(lbm_value c){
909
910
2/2
✓ Branch 1 taken 244984030 times.
✓ Branch 2 taken 168 times.
244984198 if (lbm_is_ptr(c) ){
911 244984030 lbm_cons_t *cell = lbm_ref_cell(c);
912 244984030 return cell->car;
913 }
914
915
1/2
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
168 if (lbm_is_symbol_nil(c)) {
916 168 return c; // if nil, return nil.
917 }
918
919 return ENC_SYM_TERROR;
920 }
921
922 // TODO: Many comparisons "is this the nil symbol" can be
923 // streamlined a bit. NIL is 0 and cannot be confused with any other
924 // lbm_value.
925
926 68 lbm_value lbm_caar(lbm_value c) {
927
928 lbm_value tmp;
929
930
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 if (lbm_is_ptr(c)) {
931 68 tmp = lbm_ref_cell(c)->car;
932
933
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 if (lbm_is_ptr(tmp)) {
934 68 return lbm_ref_cell(tmp)->car;
935 } else if (lbm_is_symbol_nil(tmp)) {
936 return tmp;
937 }
938 } else if (lbm_is_symbol_nil(c)){
939 return c;
940 }
941 return ENC_SYM_TERROR;
942 }
943
944
945 11564 lbm_value lbm_cadr(lbm_value c) {
946
947 lbm_value tmp;
948
949
1/2
✓ Branch 1 taken 11564 times.
✗ Branch 2 not taken.
11564 if (lbm_is_ptr(c)) {
950 11564 tmp = lbm_ref_cell(c)->cdr;
951
952
1/2
✓ Branch 1 taken 11564 times.
✗ Branch 2 not taken.
11564 if (lbm_is_ptr(tmp)) {
953 11564 return lbm_ref_cell(tmp)->car;
954 } else if (lbm_is_symbol_nil(tmp)) {
955 return tmp;
956 }
957 } else if (lbm_is_symbol_nil(c)) {
958 return c;
959 }
960 return ENC_SYM_TERROR;
961 }
962
963 112304072 lbm_value lbm_cdr(lbm_value c){
964
2/2
✓ Branch 1 taken 111737464 times.
✓ Branch 2 taken 566608 times.
112304072 if (lbm_is_ptr(c)) {
965 111737464 lbm_cons_t *cell = lbm_ref_cell(c);
966 111737464 return cell->cdr;
967 }
968
1/2
✓ Branch 1 taken 566608 times.
✗ Branch 2 not taken.
566608 if (lbm_is_symbol_nil(c)) {
969 566608 return ENC_SYM_NIL; // if nil, return nil.
970 }
971 return ENC_SYM_TERROR;
972 }
973
974 lbm_value lbm_cddr(lbm_value c) {
975 if (lbm_is_ptr(c)) {
976 lbm_value tmp = lbm_ref_cell(c)->cdr;
977 if (lbm_is_ptr(tmp)) {
978 return lbm_ref_cell(tmp)->cdr;
979 }
980 }
981 if (lbm_is_symbol_nil(c)) {
982 return ENC_SYM_NIL;
983 }
984 return ENC_SYM_TERROR;
985 }
986
987 6512490 int lbm_set_car(lbm_value c, lbm_value v) {
988 6512490 int r = 0;
989
990
2/2
✓ Branch 1 taken 6512462 times.
✓ Branch 2 taken 28 times.
6512490 if (lbm_type_of(c) == LBM_TYPE_CONS) {
991 6512462 lbm_cons_t *cell = lbm_ref_cell(c);
992 6512462 cell->car = v;
993 6512462 r = 1;
994 }
995 6512490 return r;
996 }
997
998 99145897 int lbm_set_cdr(lbm_value c, lbm_value v) {
999 99145897 int r = 0;
1000
2/2
✓ Branch 1 taken 98579373 times.
✓ Branch 2 taken 566524 times.
99145897 if (lbm_is_cons_rw(c)){
1001 98579373 lbm_cons_t *cell = lbm_ref_cell(c);
1002 98579373 cell->cdr = v;
1003 98579373 r = 1;
1004 }
1005 99145897 return r;
1006 }
1007
1008 8431652 int lbm_set_car_and_cdr(lbm_value c, lbm_value car_val, lbm_value cdr_val) {
1009 8431652 int r = 0;
1010
1/2
✓ Branch 1 taken 8431652 times.
✗ Branch 2 not taken.
8431652 if (lbm_is_cons_rw(c)) {
1011 8431652 lbm_cons_t *cell = lbm_ref_cell(c);
1012 8431652 cell->car = car_val;
1013 8431652 cell->cdr = cdr_val;
1014 8431652 r = 1;
1015 }
1016 8431652 return r;
1017 }
1018
1019 /* calculate length of a proper list */
1020 1248412 lbm_uint lbm_list_length(lbm_value c) {
1021 1248412 lbm_uint len = 0;
1022
1023
2/2
✓ Branch 1 taken 5962058 times.
✓ Branch 2 taken 1248412 times.
7210470 while (lbm_is_cons(c)){
1024 5962058 len ++;
1025 5962058 c = lbm_cdr(c);
1026 }
1027 1248412 return len;
1028 }
1029
1030 /* calculate the length of a list and check that each element
1031 fullfills the predicate pred */
1032 168 unsigned int lbm_list_length_pred(lbm_value c, bool *pres, bool (*pred)(lbm_value)) {
1033 168 bool res = true;
1034 168 unsigned int len = 0;
1035
1036
2/2
✓ Branch 1 taken 756 times.
✓ Branch 2 taken 168 times.
924 while (lbm_is_cons(c)){
1037 756 len ++;
1038
2/4
✓ Branch 0 taken 756 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
756 res = res && pred(lbm_car(c));
1039 756 c = lbm_cdr(c);
1040 }
1041 168 *pres = res;
1042 168 return len;
1043 }
1044
1045 /* reverse a proper list */
1046 lbm_value lbm_list_reverse(lbm_value list) {
1047 if (lbm_type_of(list) == LBM_TYPE_SYMBOL) {
1048 return list;
1049 }
1050
1051 lbm_value curr = list;
1052
1053 lbm_value new_list = ENC_SYM_NIL;
1054 while (lbm_is_cons(curr)) {
1055
1056 new_list = lbm_cons(lbm_car(curr), new_list);
1057 if (lbm_type_of(new_list) == LBM_TYPE_SYMBOL) {
1058 return ENC_SYM_MERROR;
1059 }
1060 curr = lbm_cdr(curr);
1061 }
1062 return new_list;
1063 }
1064
1065 168 lbm_value lbm_list_destructive_reverse(lbm_value list) {
1066
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 168 times.
168 if (lbm_type_of(list) == LBM_TYPE_SYMBOL) {
1067 return list;
1068 }
1069 168 lbm_value curr = list;
1070 168 lbm_value last_cell = ENC_SYM_NIL;
1071
1072
2/2
✓ Branch 1 taken 784 times.
✓ Branch 2 taken 168 times.
952 while (lbm_is_cons_rw(curr)) {
1073 784 lbm_value next = lbm_cdr(curr);
1074 784 lbm_set_cdr(curr, last_cell);
1075 784 last_cell = curr;
1076 784 curr = next;
1077 }
1078 168 return last_cell;
1079 }
1080
1081
1082 330014 lbm_value lbm_list_copy(int *m, lbm_value list) {
1083 330014 lbm_value curr = list;
1084 330014 lbm_uint n = lbm_list_length(list);
1085 330014 lbm_uint copy_n = n;
1086
4/4
✓ Branch 0 taken 6172 times.
✓ Branch 1 taken 323842 times.
✓ Branch 2 taken 5414 times.
✓ Branch 3 taken 758 times.
330014 if (*m >= 0 && (lbm_uint)*m < n) {
1087 5414 copy_n = (lbm_uint)*m;
1088
2/2
✓ Branch 0 taken 295456 times.
✓ Branch 1 taken 29144 times.
324600 } else if (*m == -1) {
1089 295456 *m = (int)n; // TODO: smaller range in target variable.
1090 }
1091
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 329790 times.
330014 if (copy_n == 0) return ENC_SYM_NIL;
1092 329790 lbm_uint new_list = lbm_heap_allocate_list(copy_n);
1093
2/2
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 329202 times.
329790 if (lbm_is_symbol(new_list)) return new_list;
1094 329202 lbm_value curr_targ = new_list;
1095
1096
4/4
✓ Branch 1 taken 3765710 times.
✓ Branch 2 taken 323862 times.
✓ Branch 3 taken 3760370 times.
✓ Branch 4 taken 5340 times.
4089572 while (lbm_is_cons(curr) && copy_n > 0) {
1097 3760370 lbm_value v = lbm_car(curr);
1098 3760370 lbm_set_car(curr_targ, v);
1099 3760370 curr_targ = lbm_cdr(curr_targ);
1100 3760370 curr = lbm_cdr(curr);
1101 3760370 copy_n --;
1102 }
1103
1104 329202 return new_list;
1105 }
1106
1107 // Append for proper lists only
1108 // Destructive update of list1.
1109 23576 lbm_value lbm_list_append(lbm_value list1, lbm_value list2) {
1110
1111
2/4
✓ Branch 1 taken 23576 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23576 times.
✗ Branch 4 not taken.
47152 if(lbm_is_list_rw(list1) &&
1112 23576 lbm_is_list(list2)) {
1113
1114 23576 lbm_value curr = list1;
1115
2/2
✓ Branch 2 taken 31262 times.
✓ Branch 3 taken 23576 times.
54838 while(lbm_type_of(lbm_cdr(curr)) == LBM_TYPE_CONS) {
1116 31262 curr = lbm_cdr(curr);
1117 }
1118
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 23548 times.
23576 if (lbm_is_symbol_nil(curr)) return list2;
1119 23548 lbm_set_cdr(curr, list2);
1120 23548 return list1;
1121 }
1122 return ENC_SYM_EERROR;
1123 }
1124
1125 84 lbm_value lbm_list_drop(unsigned int n, lbm_value ls) {
1126 84 lbm_value curr = ls;
1127
4/4
✓ Branch 1 taken 728 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 700 times.
✓ Branch 4 taken 28 times.
784 while (lbm_type_of_functional(curr) == LBM_TYPE_CONS &&
1128 n > 0) {
1129 700 curr = lbm_cdr(curr);
1130 700 n --;
1131 }
1132 84 return curr;
1133 }
1134
1135 150956 lbm_value lbm_index_list(lbm_value l, int32_t n) {
1136 150956 lbm_value curr = l;
1137
1138
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 150844 times.
150956 if (n < 0) {
1139 112 int32_t len = (int32_t)lbm_list_length(l);
1140 112 n = len + n;
1141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (n < 0) return ENC_SYM_NIL;
1142 }
1143
1144
4/4
✓ Branch 1 taken 227330 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 76402 times.
✓ Branch 4 taken 150928 times.
227358 while (lbm_is_cons(curr) &&
1145 n > 0) {
1146 76402 curr = lbm_cdr(curr);
1147 76402 n --;
1148 }
1149
2/2
✓ Branch 1 taken 150928 times.
✓ Branch 2 taken 28 times.
150956 if (lbm_is_cons(curr)) {
1150 150928 return lbm_car(curr);
1151 } else {
1152 28 return ENC_SYM_NIL;
1153 }
1154 }
1155
1156 // High-level arrays are just bytearrays but with a different tag and pointer type.
1157 // These arrays will be inspected by GC and the elements of the array will be marked.
1158
1159 // Arrays are part of the heap module because their lifespan is managed
1160 // by the garbage collector. The data in the array is not stored
1161 // in the "heap of cons cells".
1162 296304 int lbm_heap_allocate_array_base(lbm_value *res, bool byte_array, lbm_uint size){
1163
1164 296304 lbm_uint tag = ENC_SYM_ARRAY_TYPE;
1165 296304 lbm_uint type = LBM_TYPE_ARRAY;
1166
2/2
✓ Branch 0 taken 952 times.
✓ Branch 1 taken 295352 times.
296304 if (!byte_array) {
1167 952 tag = ENC_SYM_LISPARRAY_TYPE;
1168 952 type = LBM_TYPE_LISPARRAY;
1169 952 size = sizeof(lbm_value) * size;
1170 }
1171 296304 lbm_array_header_t *array = NULL;
1172
2/2
✓ Branch 0 taken 295352 times.
✓ Branch 1 taken 952 times.
296304 if (byte_array) {
1173 295352 array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t));
1174 } else {
1175 952 array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_extended_t));
1176 }
1177
1178
2/2
✓ Branch 0 taken 390 times.
✓ Branch 1 taken 295914 times.
296304 if (array == NULL) {
1179 390 *res = ENC_SYM_MERROR;
1180 390 return 0;
1181 }
1182 295914 array->data = NULL;
1183
1/2
✓ Branch 0 taken 295914 times.
✗ Branch 1 not taken.
295914 if ( size > 0) {
1184
2/2
✓ Branch 0 taken 952 times.
✓ Branch 1 taken 294962 times.
295914 if (!byte_array) {
1185 952 lbm_array_header_extended_t *ext_array = (lbm_array_header_extended_t*)array;
1186 952 ext_array->index = 0;
1187 }
1188
1189 295914 array->data = (lbm_uint*)lbm_malloc(size);
1190
1191
2/2
✓ Branch 0 taken 5630 times.
✓ Branch 1 taken 290284 times.
295914 if (array->data == NULL) {
1192 5630 lbm_memory_free((lbm_uint*)array);
1193 5630 *res = ENC_SYM_MERROR;
1194 5630 return 0;
1195 }
1196 // It is more important to zero out high-level arrays.
1197 // 0 is symbol NIL which is perfectly safe for the GC to inspect.
1198 290284 memset(array->data, 0, size);
1199 }
1200 290284 array->size = size;
1201
1202 // allocating a cell for array's heap-presence
1203 290284 lbm_value cell = lbm_heap_allocate_cell(type, (lbm_uint) array, tag);
1204
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 290196 times.
290284 if (cell == ENC_SYM_MERROR) {
1205 88 lbm_memory_free((lbm_uint*)array->data);
1206 88 lbm_memory_free((lbm_uint*)array);
1207 88 *res = ENC_SYM_MERROR;
1208 88 return 0;
1209 }
1210 290196 *res = cell;
1211
1212 290196 lbm_heap_state.num_alloc_arrays ++;
1213
1214 290196 return 1;
1215 }
1216
1217 295352 int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){
1218 295352 return lbm_heap_allocate_array_base(res, true, size);
1219 }
1220
1221 952 int lbm_heap_allocate_lisp_array(lbm_value *res, lbm_uint size) {
1222 952 return lbm_heap_allocate_array_base(res, false, size);
1223 }
1224
1225 // Convert a C array into an lbm_array.
1226 // if the array is in LBM_MEMORY, the lifetime will be managed by the GC after lifting.
1227 int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) {
1228
1229 lbm_array_header_t *array = NULL;
1230 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE);
1231
1232 if (cell == ENC_SYM_MERROR) {
1233 *value = cell;
1234 return 0;
1235 }
1236
1237 array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t));
1238
1239 if (array == NULL) {
1240 lbm_set_car_and_cdr(cell, ENC_SYM_NIL, ENC_SYM_NIL);
1241 *value = ENC_SYM_MERROR;
1242 return 0;
1243 }
1244
1245 array->data = (lbm_uint*)data;
1246 array->size = num_elt;
1247
1248 lbm_set_car(cell, (lbm_uint)array);
1249
1250 cell = lbm_set_ptr_type(cell, LBM_TYPE_ARRAY);
1251 *value = cell;
1252 return 1;
1253 }
1254
1255 237384 lbm_int lbm_heap_array_get_size(lbm_value arr) {
1256
1257 237384 lbm_int r = -1;
1258
1/2
✓ Branch 1 taken 237384 times.
✗ Branch 2 not taken.
237384 if (lbm_is_array_r(arr)) {
1259 237384 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237384 times.
237384 if (header == NULL) {
1261 return r;
1262 }
1263 237384 r = (lbm_int)header->size;
1264 }
1265 237384 return r;
1266 }
1267
1268 118692 const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) {
1269 118692 uint8_t *r = NULL;
1270
1/2
✓ Branch 1 taken 118692 times.
✗ Branch 2 not taken.
118692 if (lbm_is_array_r(arr)) {
1271 118692 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1272 118692 r = (uint8_t*)header->data;
1273 }
1274 118692 return r;
1275 }
1276
1277 uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) {
1278 uint8_t *r = NULL;
1279 if (lbm_is_array_rw(arr)) {
1280 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1281 r = (uint8_t*)header->data;
1282 }
1283 return r;
1284 }
1285
1286
1287 /* Explicitly freeing an array.
1288
1289 This is a highly unsafe operation and can only be safely
1290 used if the heap cell that points to the array has not been made
1291 accessible to the program.
1292
1293 So This function can be used to free an array in case an array
1294 is being constructed and some error case appears while doing so
1295 If the array still have not become available it can safely be
1296 "explicitly" freed.
1297
1298 The problem is that if the "array" heap-cell is made available to
1299 the program, this cell can easily be duplicated and we would have
1300 to search the entire heap to find all cells pointing to the array
1301 memory in question and "null"-them out before freeing the memory
1302 */
1303
1304 112 int lbm_heap_explicit_free_array(lbm_value arr) {
1305
1306 112 int r = 0;
1307
2/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
112 if (lbm_is_array_rw(arr) && lbm_cdr(arr) == ENC_SYM_ARRAY_TYPE) {
1308 112 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (header == NULL) {
1310 return 0;
1311 }
1312 112 lbm_memory_free((lbm_uint*)header->data);
1313 112 lbm_memory_free((lbm_uint*)header);
1314
1315 112 arr = lbm_set_ptr_type(arr, LBM_TYPE_CONS);
1316 112 lbm_set_car(arr, ENC_SYM_NIL);
1317 112 lbm_set_cdr(arr, ENC_SYM_NIL);
1318 112 r = 1;
1319 }
1320
1321 112 return r;
1322 }
1323
1324 lbm_uint lbm_size_of(lbm_type t) {
1325 lbm_uint s = 0;
1326 switch(t) {
1327 case LBM_TYPE_BYTE:
1328 s = 1;
1329 break;
1330 case LBM_TYPE_I: /* fall through */
1331 case LBM_TYPE_U:
1332 case LBM_TYPE_SYMBOL:
1333 s = sizeof(lbm_uint);
1334 break;
1335 case LBM_TYPE_I32: /* fall through */
1336 case LBM_TYPE_U32:
1337 case LBM_TYPE_FLOAT:
1338 s = 4;
1339 break;
1340 case LBM_TYPE_I64: /* fall through */
1341 case LBM_TYPE_U64:
1342 case LBM_TYPE_DOUBLE:
1343 s = 8;
1344 break;
1345 }
1346 return s;
1347 }
1348
1349 static bool dummy_flash_write(lbm_uint ix, lbm_uint val) {
1350 (void)ix;
1351 (void)val;
1352 return false;
1353 }
1354
1355 static const_heap_write_fun const_heap_write = dummy_flash_write;
1356
1357 21504 int lbm_const_heap_init(const_heap_write_fun w_fun,
1358 lbm_const_heap_t *heap,
1359 lbm_uint *addr,
1360 lbm_uint num_words) {
1361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21504 times.
21504 if (((uintptr_t)addr % 4) != 0) return 0;
1362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21504 times.
21504 if ((num_words % 2) != 0) return 0;
1363
1364
1/2
✓ Branch 0 taken 21504 times.
✗ Branch 1 not taken.
21504 if (!lbm_const_heap_mutex_initialized) {
1365 21504 mutex_init(&lbm_const_heap_mutex);
1366 21504 lbm_const_heap_mutex_initialized = true;
1367 }
1368
1369
1/2
✓ Branch 0 taken 21504 times.
✗ Branch 1 not taken.
21504 if (!lbm_mark_mutex_initialized) {
1370 21504 mutex_init(&lbm_mark_mutex);
1371 21504 lbm_mark_mutex_initialized = true;
1372 }
1373
1374 21504 const_heap_write = w_fun;
1375
1376 21504 heap->heap = addr;
1377 21504 heap->size = num_words;
1378 21504 heap->next = 0;
1379
1380 21504 lbm_const_heap_state = heap;
1381 // ref_cell views the lbm_uint array as an lbm_cons_t array
1382 21504 lbm_heaps[1] = (lbm_cons_t*)addr;
1383 21504 return 1;
1384 }
1385
1386 2408 lbm_flash_status lbm_allocate_const_cell(lbm_value *res) {
1387 2408 lbm_flash_status r = LBM_FLASH_FULL;
1388
1389 2408 mutex_lock(&lbm_const_heap_mutex);
1390 // waste a cell if we have ended up unaligned after writing an array to flash.
1391
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 2380 times.
2408 if (lbm_const_heap_state->next % 2 == 1) {
1392 28 lbm_const_heap_state->next++;
1393 }
1394
1395
1/2
✓ Branch 0 taken 2408 times.
✗ Branch 1 not taken.
2408 if (lbm_const_heap_state &&
1396
1/2
✓ Branch 0 taken 2408 times.
✗ Branch 1 not taken.
2408 (lbm_const_heap_state->next+1) < lbm_const_heap_state->size) {
1397 // A cons cell uses two words.
1398 2408 lbm_value cell = lbm_const_heap_state->next;
1399 2408 lbm_const_heap_state->next += 2;
1400 2408 *res = (cell << LBM_ADDRESS_SHIFT) | LBM_PTR_BIT | LBM_TYPE_CONS | LBM_PTR_TO_CONSTANT_BIT;
1401 2408 r = LBM_FLASH_WRITE_OK;
1402 }
1403 2408 mutex_unlock(&lbm_const_heap_mutex);
1404 2408 return r;
1405 }
1406
1407 28 lbm_flash_status lbm_allocate_const_raw(lbm_uint nwords, lbm_uint *res) {
1408 28 lbm_flash_status r = LBM_FLASH_FULL;
1409
1410
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (lbm_const_heap_state &&
1411
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 (lbm_const_heap_state->next + nwords) < lbm_const_heap_state->size) {
1412 28 lbm_uint ix = lbm_const_heap_state->next;
1413 28 *res = (lbm_uint)&lbm_const_heap_state->heap[ix];
1414 28 lbm_const_heap_state->next += nwords;
1415 28 r = LBM_FLASH_WRITE_OK;
1416 }
1417 28 return r;
1418 }
1419
1420 462 lbm_flash_status lbm_write_const_raw(lbm_uint *data, lbm_uint n, lbm_uint *res) {
1421
1422 462 lbm_flash_status r = LBM_FLASH_FULL;
1423
1424
1/2
✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
462 if (lbm_const_heap_state &&
1425
1/2
✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
462 (lbm_const_heap_state->next + n) < lbm_const_heap_state->size) {
1426 462 lbm_uint ix = lbm_const_heap_state->next;
1427
1428
2/2
✓ Branch 0 taken 980 times.
✓ Branch 1 taken 462 times.
1442 for (unsigned int i = 0; i < n; i ++) {
1429
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 980 times.
980 if (!const_heap_write(ix + i, ((lbm_uint*)data)[i]))
1430 return LBM_FLASH_WRITE_ERROR;
1431 }
1432 462 lbm_const_heap_state->next += n;
1433 462 *res = (lbm_uint)&lbm_const_heap_state->heap[ix];
1434 462 r = LBM_FLASH_WRITE_OK;
1435 }
1436 462 return r;
1437 }
1438
1439 84 lbm_flash_status lbm_const_write(lbm_uint *tgt, lbm_uint val) {
1440
1441
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (lbm_const_heap_state) {
1442 84 lbm_uint flash = (lbm_uint)lbm_const_heap_state->heap;
1443 84 lbm_uint ix = (((lbm_uint)tgt - flash) / sizeof(lbm_uint)); // byte address to ix
1444
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 if (const_heap_write(ix, val)) {
1445 84 return LBM_FLASH_WRITE_OK;
1446 }
1447 return LBM_FLASH_WRITE_ERROR;
1448 }
1449 return LBM_FLASH_FULL;
1450 }
1451
1452 2408 lbm_flash_status write_const_cdr(lbm_value cell, lbm_value val) {
1453 2408 lbm_uint addr = lbm_dec_ptr(cell);
1454
1/2
✓ Branch 1 taken 2408 times.
✗ Branch 2 not taken.
2408 if (const_heap_write(addr+1, val))
1455 2408 return LBM_FLASH_WRITE_OK;
1456 return LBM_FLASH_WRITE_ERROR;
1457 }
1458
1459 2408 lbm_flash_status write_const_car(lbm_value cell, lbm_value val) {
1460 2408 lbm_uint addr = lbm_dec_ptr(cell);
1461
1/2
✓ Branch 1 taken 2408 times.
✗ Branch 2 not taken.
2408 if (const_heap_write(addr, val))
1462 2408 return LBM_FLASH_WRITE_OK;
1463 return LBM_FLASH_WRITE_ERROR;
1464 }
1465
1466 lbm_uint lbm_flash_memory_usage(void) {
1467 return lbm_const_heap_state->next;
1468 }
1469