Bug Summary

File:heap.c
Warning:line 701, column 41
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'arr')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple i386-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name heap.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu i686 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/joels/Current/lispbm -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -I ./include -I ./include/extensions -I platform/linux/include -D _PRELUDE -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/joels/Current/lispbm -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/joels/Current/lispbm/test_reports/version_0.24.0/scan-build/2024-04-28-134646-49849-1 -x c src/heap.c

src/heap.c

1/*
2 Copyright 2018, 2020, 2022, 2023 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
27#include "heap.h"
28#include "symrepr.h"
29#include "stack.h"
30#include "lbm_channel.h"
31#include "platform_mutex.h"
32#include "eval_cps.h"
33#ifdef VISUALIZE_HEAP
34#include "heap_vis.h"
35#endif
36
37
38static inline lbm_value lbm_set_gc_mark(lbm_value x) {
39 return x | LBM_GC_MARKED0x00000002u;
40}
41
42static inline lbm_value lbm_clr_gc_mark(lbm_value x) {
43 return x & ~LBM_GC_MASK0x00000002u;
44}
45
46static inline bool_Bool lbm_get_gc_mark(lbm_value x) {
47 return x & LBM_GC_MASK0x00000002u;
48}
49
50// flag is the same bit as mark, but in car
51static inline bool_Bool lbm_get_gc_flag(lbm_value x) {
52 return x & LBM_GC_MARKED0x00000002u;
53}
54
55static inline lbm_value lbm_set_gc_flag(lbm_value x) {
56 return x | LBM_GC_MARKED0x00000002u;
57}
58
59static inline lbm_value lbm_clr_gc_flag(lbm_value x) {
60 return x & ~LBM_GC_MASK0x00000002u;
61}
62
63
64lbm_heap_state_t lbm_heap_state;
65
66lbm_const_heap_t *lbm_const_heap_state;
67
68lbm_cons_t *lbm_heaps[2] = {NULL((void*)0), NULL((void*)0)};
69
70static mutex_t lbm_const_heap_mutex;
71static bool_Bool lbm_const_heap_mutex_initialized = false0;
72
73static mutex_t lbm_mark_mutex;
74static bool_Bool lbm_mark_mutex_initialized = false0;
75
76#ifdef USE_GC_PTR_REV
77void lbm_gc_lock(void) {
78 mutex_lock(&lbm_mark_mutex);
79}
80void lbm_gc_unlock(void) {
81 mutex_unlock(&lbm_mark_mutex);
82}
83#else
84void lbm_gc_lock(void) {
85}
86void lbm_gc_unlock(void) {
87}
88#endif
89
90/****************************************************/
91/* ENCODERS DECODERS */
92
93lbm_value lbm_enc_i32(int32_t x) {
94#ifndef LBM64
95 lbm_value i = lbm_cons((lbm_uint)x, lbm_enc_sym(SYM_RAW_I_TYPE0x31));
96 if (lbm_type_of(i) == LBM_TYPE_SYMBOL0x00000000u) return i;
97 return lbm_set_ptr_type(i, LBM_TYPE_I320x28000000u);
98#else
99 return (((lbm_uint)x) << LBM_VAL_SHIFT4) | LBM_TYPE_I320x28000000u;
100#endif
101}
102
103lbm_value lbm_enc_u32(uint32_t x) {
104#ifndef LBM64
105 lbm_value u = lbm_cons(x, lbm_enc_sym(SYM_RAW_U_TYPE0x32));
106 if (lbm_type_of(u) == LBM_TYPE_SYMBOL0x00000000u) return u;
107 return lbm_set_ptr_type(u, LBM_TYPE_U320x38000000u);
108#else
109 return (((lbm_uint)x) << LBM_VAL_SHIFT4) | LBM_TYPE_U320x38000000u;
110#endif
111}
112
113lbm_value lbm_enc_float(float x) {
114#ifndef LBM64
115 lbm_uint t;
116 memcpy(&t, &x, sizeof(lbm_float));
117 lbm_value f = lbm_cons(t, lbm_enc_sym(SYM_RAW_F_TYPE0x33));
118 if (lbm_type_of(f) == LBM_TYPE_SYMBOL0x00000000u) return f;
119 return lbm_set_ptr_type(f, LBM_TYPE_FLOAT0x68000000u);
120#else
121 lbm_uint t = 0;
122 memcpy(&t, &x, sizeof(float));
123 return (((lbm_uint)t) << LBM_VAL_SHIFT4) | LBM_TYPE_FLOAT0x68000000u;
124#endif
125}
126
127lbm_value lbm_enc_i64(int64_t x) {
128#ifndef LBM64
129 lbm_value res = lbm_enc_sym(SYM_MERROR0x23);
130 lbm_uint* storage = lbm_memory_allocate(2);
131 if (storage) {
132 res = lbm_cons((lbm_uint)storage, lbm_enc_sym(SYM_IND_I_TYPE0x34));
133 if (lbm_type_of(res) != LBM_TYPE_SYMBOL0x00000000u) {
134 memcpy(storage,&x, 8);
135 res = lbm_set_ptr_type(res, LBM_TYPE_I640x48000000u);
136 }
137 }
138 return res;
139#else
140 lbm_value u = lbm_cons((uint64_t)x, lbm_enc_sym(SYM_RAW_I_TYPE0x31));
141 if (lbm_type_of(u) == LBM_TYPE_SYMBOL0x00000000u) return u;
142 return lbm_set_ptr_type(u, LBM_TYPE_I640x48000000u);
143#endif
144}
145
146lbm_value lbm_enc_u64(uint64_t x) {
147#ifndef LBM64
148 lbm_value res = lbm_enc_sym(SYM_MERROR0x23);
149 uint8_t* storage = lbm_malloc(sizeof(uint64_t));
150 if (storage) {
151 res = lbm_cons((lbm_uint)storage, lbm_enc_sym(SYM_IND_U_TYPE0x35));
152 if (lbm_type_of(res) != LBM_TYPE_SYMBOL0x00000000u) {
153 memcpy(storage,&x, sizeof(uint64_t));
154 res = lbm_set_ptr_type(res, LBM_TYPE_U640x58000000u);
155 }
156 }
157 return res;
158#else
159 lbm_value u = lbm_cons(x, lbm_enc_sym(SYM_RAW_U_TYPE0x32));
160 if (lbm_type_of(u) == LBM_TYPE_SYMBOL0x00000000u) return u;
161 return lbm_set_ptr_type(u, LBM_TYPE_U640x58000000u);
162#endif
163}
164
165lbm_value lbm_enc_double(double x) {
166#ifndef LBM64
167 lbm_value res = lbm_enc_sym(SYM_MERROR0x23);
168 lbm_uint* storage = lbm_memory_allocate(2);
169 if (storage) {
170 res = lbm_cons((lbm_uint)storage, lbm_enc_sym(SYM_IND_F_TYPE0x36));
171 if (lbm_type_of(res) != LBM_TYPE_SYMBOL0x00000000u) {
172 memcpy(storage,&x, 8);
173 res = lbm_set_ptr_type(res, LBM_TYPE_DOUBLE0x78000000u);
174 }
175 }
176 return res;
177#else
178 lbm_uint t;
179 memcpy(&t, &x, sizeof(double));
180 lbm_value f = lbm_cons(t, lbm_enc_sym(SYM_RAW_F_TYPE0x33));
181 if (lbm_type_of(f) == LBM_TYPE_SYMBOL0x00000000u) return f;
182 return lbm_set_ptr_type(f, LBM_TYPE_DOUBLE0x78000000u);
183#endif
184}
185
186float lbm_dec_float(lbm_value x) {
187#ifndef LBM64
188 float f_tmp;
189 lbm_uint tmp = lbm_car(x);
190 memcpy(&f_tmp, &tmp, sizeof(float));
191 return f_tmp;
192#else
193 uint32_t tmp = (uint32_t)(x >> LBM_VAL_SHIFT4);
194 float f_tmp;
195 memcpy(&f_tmp, &tmp, sizeof(float));
196 return f_tmp;
197#endif
198}
199
200double lbm_dec_double(lbm_value x) {
201#ifndef LBM64
202 double d;
203 uint32_t *data = (uint32_t*)lbm_car(x);
204 if (data == NULL((void*)0)) return 0; // no good way to report error from here currently.
205 memcpy(&d, data, sizeof(double));
206 return d;
207#else
208 double f_tmp;
209 lbm_uint tmp = lbm_car(x);
210 memcpy(&f_tmp, &tmp, sizeof(double));
211 return f_tmp;
212#endif
213}
214
215uint64_t lbm_dec_u64(lbm_value x) {
216#ifndef LBM64
217 uint64_t u;
218 uint32_t *data = (uint32_t*)lbm_car(x);
219 if (data == NULL((void*)0)) return 0;
220 memcpy(&u, data, 8);
221 return u;
222#else
223 return (uint64_t)lbm_car(x);
224#endif
225}
226
227int64_t lbm_dec_i64(lbm_value x) {
228#ifndef LBM64
229 int64_t i;
230 uint32_t *data = (uint32_t*)lbm_car(x);
231 if (data == NULL((void*)0)) return 0;
232 memcpy(&i, data, 8);
233 return i;
234#else
235 return (int64_t)lbm_car(x);
236#endif
237}
238
239char *lbm_dec_str(lbm_value val) {
240 char *res = 0;
241 if (lbm_is_array_r(val)) {
242 lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(val);
243 if (array) {
244 res = (char *)array->data;
245 }
246 }
247 return res;
248}
249
250lbm_char_channel_t *lbm_dec_channel(lbm_value val) {
251 lbm_char_channel_t *res = NULL((void*)0);
252
253 if (lbm_type_of(val) == LBM_TYPE_CHANNEL0x90000000u) {
254 res = (lbm_char_channel_t *)lbm_car(val);
255 }
256 return res;
257}
258
259lbm_uint lbm_dec_custom(lbm_value val) {
260 lbm_uint res = 0;
261 if (lbm_type_of(val) == LBM_TYPE_CUSTOM0xA0000000u) {
262 res = (lbm_uint)lbm_car(val);
263 }
264 return res;
265}
266
267uint8_t lbm_dec_as_char(lbm_value a) {
268 switch (lbm_type_of_functional(a)) {
269 case LBM_TYPE_CHAR0x00000004u:
270 return (uint8_t) lbm_dec_char(a);
271 case LBM_TYPE_I0x00000008u:
272 return (uint8_t) lbm_dec_i(a);
273 case LBM_TYPE_U0x0000000Cu:
274 return (uint8_t) lbm_dec_u(a);
275 case LBM_TYPE_I320x28000000u:
276 return (uint8_t) lbm_dec_i32(a);
277 case LBM_TYPE_U320x38000000u:
278 return (uint8_t) lbm_dec_u32(a);
279 case LBM_TYPE_FLOAT0x68000000u:
280 return (uint8_t)lbm_dec_float(a);
281 case LBM_TYPE_I640x48000000u:
282 return (uint8_t) lbm_dec_i64(a);
283 case LBM_TYPE_U640x58000000u:
284 return (uint8_t) lbm_dec_u64(a);
285 case LBM_TYPE_DOUBLE0x78000000u:
286 return (uint8_t) lbm_dec_double(a);
287 }
288 return 0;
289}
290
291uint32_t lbm_dec_as_u32(lbm_value a) {
292 switch (lbm_type_of_functional(a)) {
293 case LBM_TYPE_CHAR0x00000004u:
294 return (uint32_t) lbm_dec_char(a);
295 case LBM_TYPE_I0x00000008u:
296 return (uint32_t) lbm_dec_i(a);
297 case LBM_TYPE_U0x0000000Cu:
298 return (uint32_t) lbm_dec_u(a);
299 case LBM_TYPE_I320x28000000u: /* fall through */
300 case LBM_TYPE_U320x38000000u:
301 return (uint32_t) lbm_dec_u32(a);
302 case LBM_TYPE_FLOAT0x68000000u:
303 return (uint32_t)lbm_dec_float(a);
304 case LBM_TYPE_I640x48000000u:
305 return (uint32_t) lbm_dec_i64(a);
306 case LBM_TYPE_U640x58000000u:
307 return (uint32_t) lbm_dec_u64(a);
308 case LBM_TYPE_DOUBLE0x78000000u:
309 return (uint32_t) lbm_dec_double(a);
310 }
311 return 0;
312}
313
314int32_t lbm_dec_as_i32(lbm_value a) {
315 switch (lbm_type_of_functional(a)) {
316 case LBM_TYPE_CHAR0x00000004u:
317 return (int32_t) lbm_dec_char(a);
318 case LBM_TYPE_I0x00000008u:
319 return (int32_t) lbm_dec_i(a);
320 case LBM_TYPE_U0x0000000Cu:
321 return (int32_t) lbm_dec_u(a);
322 case LBM_TYPE_I320x28000000u:
323 return (int32_t) lbm_dec_i32(a);
324 case LBM_TYPE_U320x38000000u:
325 return (int32_t) lbm_dec_u32(a);
326 case LBM_TYPE_FLOAT0x68000000u:
327 return (int32_t) lbm_dec_float(a);
328 case LBM_TYPE_I640x48000000u:
329 return (int32_t) lbm_dec_i64(a);
330 case LBM_TYPE_U640x58000000u:
331 return (int32_t) lbm_dec_u64(a);
332 case LBM_TYPE_DOUBLE0x78000000u:
333 return (int32_t) lbm_dec_double(a);
334
335 }
336 return 0;
337}
338
339int64_t lbm_dec_as_i64(lbm_value a) {
340 switch (lbm_type_of_functional(a)) {
341 case LBM_TYPE_CHAR0x00000004u:
342 return (int64_t) lbm_dec_char(a);
343 case LBM_TYPE_I0x00000008u:
344 return lbm_dec_i(a);
345 case LBM_TYPE_U0x0000000Cu:
346 return (int64_t) lbm_dec_u(a);
347 case LBM_TYPE_I320x28000000u:
348 return (int64_t) lbm_dec_i32(a);
349 case LBM_TYPE_U320x38000000u:
350 return (int64_t) lbm_dec_u32(a);
351 case LBM_TYPE_FLOAT0x68000000u:
352 return (int64_t) lbm_dec_float(a);
353 case LBM_TYPE_I640x48000000u:
354 return (int64_t) lbm_dec_i64(a);
355 case LBM_TYPE_U640x58000000u:
356 return (int64_t) lbm_dec_u64(a);
357 case LBM_TYPE_DOUBLE0x78000000u:
358 return (int64_t) lbm_dec_double(a);
359 }
360 return 0;
361}
362
363uint64_t lbm_dec_as_u64(lbm_value a) {
364 switch (lbm_type_of_functional(a)) {
365 case LBM_TYPE_CHAR0x00000004u:
366 return (uint64_t) lbm_dec_char(a);
367 case LBM_TYPE_I0x00000008u:
368 return (uint64_t) lbm_dec_i(a);
369 case LBM_TYPE_U0x0000000Cu:
370 return lbm_dec_u(a);
371 case LBM_TYPE_I320x28000000u:
372 return (uint64_t) lbm_dec_i32(a);
373 case LBM_TYPE_U320x38000000u:
374 return (uint64_t) lbm_dec_u32(a);
375 case LBM_TYPE_FLOAT0x68000000u:
376 return (uint64_t)lbm_dec_float(a);
377 case LBM_TYPE_I640x48000000u:
378 return (uint64_t) lbm_dec_i64(a);
379 case LBM_TYPE_U640x58000000u:
380 return (uint64_t) lbm_dec_u64(a);
381 case LBM_TYPE_DOUBLE0x78000000u:
382 return (uint64_t) lbm_dec_double(a);
383 }
384 return 0;
385}
386
387float lbm_dec_as_float(lbm_value a) {
388
389 switch (lbm_type_of_functional(a)) {
390 case LBM_TYPE_CHAR0x00000004u:
391 return (float) lbm_dec_char(a);
392 case LBM_TYPE_I0x00000008u:
393 return (float) lbm_dec_i(a);
394 case LBM_TYPE_U0x0000000Cu:
395 return (float) lbm_dec_u(a);
396 case LBM_TYPE_I320x28000000u:
397 return (float) lbm_dec_i32(a);
398 case LBM_TYPE_U320x38000000u:
399 return (float) lbm_dec_u32(a);
400 case LBM_TYPE_FLOAT0x68000000u:
401 return (float) lbm_dec_float(a);
402 case LBM_TYPE_I640x48000000u:
403 return (float) lbm_dec_i64(a);
404 case LBM_TYPE_U640x58000000u:
405 return (float) lbm_dec_u64(a);
406 case LBM_TYPE_DOUBLE0x78000000u:
407 return (float) lbm_dec_double(a);
408 }
409 return 0;
410}
411
412double lbm_dec_as_double(lbm_value a) {
413
414 switch (lbm_type_of_functional(a)) {
415 case LBM_TYPE_CHAR0x00000004u:
416 return (double) lbm_dec_char(a);
417 case LBM_TYPE_I0x00000008u:
418 return (double) lbm_dec_i(a);
419 case LBM_TYPE_U0x0000000Cu:
420 return (double) lbm_dec_u(a);
421 case LBM_TYPE_I320x28000000u:
422 return (double) lbm_dec_i32(a);
423 case LBM_TYPE_U320x38000000u:
424 return (double) lbm_dec_u32(a);
425 case LBM_TYPE_FLOAT0x68000000u:
426 return (double) lbm_dec_float(a);
427 case LBM_TYPE_I640x48000000u:
428 return (double) lbm_dec_i64(a);
429 case LBM_TYPE_U640x58000000u:
430 return (double) lbm_dec_u64(a);
431 case LBM_TYPE_DOUBLE0x78000000u:
432 return (double) lbm_dec_double(a);
433 }
434 return 0;
435}
436
437/****************************************************/
438/* HEAP MANAGEMENT */
439
440static int generate_freelist(size_t num_cells) {
441 size_t i = 0;
442
443 if (!lbm_heap_state.heap) return 0;
444
445 lbm_heap_state.freelist = lbm_enc_cons_ptr(0);
446
447 lbm_cons_t *t;
448
449 // Add all cells to free list
450 for (i = 1; i < num_cells; i ++) {
451 t = lbm_ref_cell(lbm_enc_cons_ptr(i-1));
452 t->car = ENC_SYM_RECOVERED(((0x28) << 4) | 0x00000000u); // all cars in free list are "RECOVERED"
453 t->cdr = lbm_enc_cons_ptr(i);
454 }
455
456 // Replace the incorrect pointer at the last cell.
457 t = lbm_ref_cell(lbm_enc_cons_ptr(num_cells-1));
458 t->cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
459
460 return 1;
461}
462
463void lbm_nil_freelist(void) {
464 lbm_heap_state.freelist = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
465 lbm_heap_state.num_alloc = lbm_heap_state.heap_size;
466}
467
468static void heap_init_state(lbm_cons_t *addr, lbm_uint num_cells,
469 lbm_uint* gc_stack_storage, lbm_uint gc_stack_size) {
470 lbm_heap_state.heap = addr;
471 lbm_heap_state.heap_bytes = (unsigned int)(num_cells * sizeof(lbm_cons_t));
472 lbm_heap_state.heap_size = num_cells;
473
474 lbm_stack_create(&lbm_heap_state.gc_stack, gc_stack_storage, gc_stack_size);
475
476 lbm_heap_state.num_alloc = 0;
477 lbm_heap_state.num_alloc_arrays = 0;
478 lbm_heap_state.gc_num = 0;
479 lbm_heap_state.gc_marked = 0;
480 lbm_heap_state.gc_recovered = 0;
481 lbm_heap_state.gc_recovered_arrays = 0;
482 lbm_heap_state.gc_least_free = num_cells;
483 lbm_heap_state.gc_last_free = num_cells;
484}
485
486void lbm_heap_new_freelist_length(void) {
487 lbm_uint l = lbm_heap_state.heap_size - lbm_heap_state.num_alloc;
488 lbm_heap_state.gc_last_free = l;
489 if (l < lbm_heap_state.gc_least_free)
490 lbm_heap_state.gc_least_free = l;
491}
492
493int lbm_heap_init(lbm_cons_t *addr, lbm_uint num_cells,
494 lbm_uint gc_stack_size) {
495
496 if (((uintptr_t)addr % 8) != 0) return 0;
497
498 memset(addr,0, sizeof(lbm_cons_t) * num_cells);
499
500 lbm_uint *gc_stack_storage = (lbm_uint*)lbm_malloc(gc_stack_size * sizeof(lbm_uint));
501 if (gc_stack_storage == NULL((void*)0)) return 0;
502
503 heap_init_state(addr, num_cells,
504 gc_stack_storage, gc_stack_size);
505
506 lbm_heaps[0] = addr;
507
508 return generate_freelist(num_cells);
509}
510
511lbm_uint lbm_heap_num_free(void) {
512 return lbm_heap_state.heap_size - lbm_heap_state.num_alloc;
513}
514
515lbm_value lbm_heap_allocate_cell(lbm_type ptr_type, lbm_value car, lbm_value cdr) {
516 lbm_value res;
517 // it is a ptr replace freelist with cdr of freelist;
518 res = lbm_heap_state.freelist;
519 if (lbm_type_of(res) == LBM_TYPE_CONS0x10000000u) {
520 lbm_uint heap_ix = lbm_dec_ptr(res);
521 lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr;
522 lbm_heap_state.num_alloc++;
523 lbm_heap_state.heap[heap_ix].car = car;
524 lbm_heap_state.heap[heap_ix].cdr = cdr;
525 res = lbm_set_ptr_type(res, ptr_type);
526 return res;
527 }
528 return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
529}
530
531lbm_value lbm_heap_allocate_list(lbm_uint n) {
532 if (n == 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
533 if (lbm_heap_num_free() < n) return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
534
535 lbm_value curr = lbm_heap_state.freelist;
536 lbm_value res = curr;
537 if (lbm_type_of(curr) == LBM_TYPE_CONS0x10000000u) {
538
539 lbm_cons_t *c_cell = NULL((void*)0);
540 lbm_uint count = 0;
541 do {
542 c_cell = lbm_ref_cell(curr);
543 c_cell->car = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
544 curr = c_cell->cdr;
545 count ++;
546 } while (count < n);
547 lbm_heap_state.freelist = curr;
548 c_cell->cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
549 lbm_heap_state.num_alloc+=count;
550 return res;
551 }
552 return ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u);
553}
554
555lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) {
556 if (n == 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
557 if (lbm_heap_num_free() < n) return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
558
559 lbm_value curr = lbm_heap_state.freelist;
560 lbm_value res = curr;
561 if (lbm_type_of(curr) == LBM_TYPE_CONS0x10000000u) {
562
563 lbm_cons_t *c_cell = NULL((void*)0);
564 unsigned int count = 0;
565 do {
566 c_cell = lbm_ref_cell(curr);
567 c_cell->car = va_arg(valist, lbm_value)__builtin_va_arg(valist, lbm_value);
568 curr = c_cell->cdr;
569 count ++;
570 } while (count < n);
571 lbm_heap_state.freelist = curr;
572 c_cell->cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
573 lbm_heap_state.num_alloc+=count;
574 return res;
575 }
576 return ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u);
577}
578
579lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) {
580 va_list valist;
581 va_start(valist, n)__builtin_va_start(valist, n);
582 lbm_value r = lbm_heap_allocate_list_init_va(n, valist);
583 va_end(valist)__builtin_va_end(valist);
584 return r;
585}
586
587lbm_uint lbm_heap_num_allocated(void) {
588 return lbm_heap_state.num_alloc;
589}
590lbm_uint lbm_heap_size(void) {
591 return lbm_heap_state.heap_size;
592}
593
594lbm_uint lbm_heap_size_bytes(void) {
595 return lbm_heap_state.heap_bytes;
596}
597
598void lbm_get_heap_state(lbm_heap_state_t *res) {
599 *res = lbm_heap_state;
600}
601
602lbm_uint lbm_get_gc_stack_max(void) {
603 return lbm_heap_state.gc_stack.max_sp;
604}
605
606lbm_uint lbm_get_gc_stack_size(void) {
607 return lbm_heap_state.gc_stack.size;
608}
609
610#ifdef USE_GC_PTR_REV
611static inline void value_assign(lbm_value *a, lbm_value b) {
612 lbm_value a_old = *a & LBM_GC_MASK0x00000002u;
613 *a = a_old | (b & ~LBM_GC_MASK0x00000002u);
614}
615
616void lbm_gc_mark_phase(lbm_value root) {
617 bool_Bool work_to_do = true1;
618
619 if (!lbm_is_ptr(root)) return;
620
621 mutex_lock(&lbm_const_heap_mutex);
622 lbm_value curr = root;
623 lbm_value prev = lbm_enc_cons_ptr(LBM_PTR_NULL(0x03FFFFFCu >> 2));
624
625 while (work_to_do) {
626 // follow leftwards pointers
627 while (lbm_is_ptr(curr) &&
628 (lbm_dec_ptr(curr) != LBM_PTR_NULL(0x03FFFFFCu >> 2)) &&
629 ((curr & LBM_PTR_TO_CONSTANT_BIT0x04000000u) == 0) &&
630 !lbm_get_gc_mark(lbm_cdr(curr))) {
631 // Mark the cell if not a constant cell
632 lbm_cons_t *cell = lbm_ref_cell(curr);
633 cell->cdr = lbm_set_gc_mark(cell->cdr);
634 if (lbm_is_cons_rw(curr)) {
635 lbm_value next = 0;
636 value_assign(&next, cell->car);
637 value_assign(&cell->car, prev);
638 value_assign(&prev,curr);
639 value_assign(&curr, next);
640 }
641 // Will jump out next iteration as gc mark is set in curr.
642 }
643 while (lbm_is_ptr(prev) &&
644 (lbm_dec_ptr(prev) != LBM_PTR_NULL(0x03FFFFFCu >> 2)) &&
645 lbm_get_gc_flag(lbm_car(prev)) ) {
646 // clear the flag
647 lbm_cons_t *cell = lbm_ref_cell(prev);
648 cell->car = lbm_clr_gc_flag(cell->car);
649 lbm_value next = 0;
650 value_assign(&next, cell->cdr);
651 value_assign(&cell->cdr, curr);
652 value_assign(&curr, prev);
653 value_assign(&prev, next);
654 }
655 if (lbm_is_ptr(prev) &&
656 lbm_dec_ptr(prev) == LBM_PTR_NULL(0x03FFFFFCu >> 2)) {
657 work_to_do = false0;
658 } else if (lbm_is_ptr(prev)) {
659 // set the flag
660 lbm_cons_t *cell = lbm_ref_cell(prev);
661 cell->car = lbm_set_gc_flag(cell->car);
662 lbm_value next = 0;
663 value_assign(&next, cell->car);
664 value_assign(&cell->car, curr);
665 value_assign(&curr, cell->cdr);
666 value_assign(&cell->cdr, next);
667 }
668 }
669 mutex_unlock(&lbm_const_heap_mutex);
670}
671
672#else
673extern eval_context_t *ctx_running;
674void lbm_gc_mark_phase(lbm_value root) {
675
676 lbm_stack_t *s = &lbm_heap_state.gc_stack;
677 s->data[s->sp++] = root;
678
679 while (!lbm_stack_is_empty(s)) {
4
Calling 'lbm_stack_is_empty'
8
Returning from 'lbm_stack_is_empty'
9
Loop condition is true. Entering loop body
680 lbm_value curr;
681 lbm_pop(s, &curr);
682
683 mark_shortcut:
684 if (!lbm_is_ptr(curr) || (curr & LBM_PTR_TO_CONSTANT_BIT0x04000000u)) {
10
Assuming the condition is false
11
Assuming the condition is false
12
Taking false branch
685 continue;
686 }
687
688 lbm_cons_t *cell = &lbm_heap_state.heap[lbm_dec_ptr(curr)];
689
690 if (lbm_get_gc_mark(cell->cdr)) continue;
13
Assuming the condition is false
14
Taking false branch
691 cell->cdr = lbm_set_gc_mark(cell->cdr);
692 lbm_heap_state.gc_marked ++;
693
694 lbm_value t_ptr = lbm_type_of(curr);
695
696 if (t_ptr >= LBM_NON_CONS_POINTER_TYPE_FIRST0x20000000u &&
15
Assuming 't_ptr' is < LBM_NON_CONS_POINTER_TYPE_FIRST
697 t_ptr <= LBM_NON_CONS_POINTER_TYPE_LAST0xAC000000u) continue;
698
699 if (cell->car == ENC_SYM_CONT(((0x10E) << 4) | 0x00000000u)) {
16
Assuming the condition is true
17
Taking true branch
700 lbm_array_header_t *arr = (lbm_array_header_t*)lbm_car(cell->cdr);
18
Calling 'lbm_car'
24
Returning from 'lbm_car'
25
'arr' initialized to a null pointer value
701 lbm_value *arrdata = (lbm_value *)arr->data;
26
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'arr')
702 for (lbm_uint i = 0; i < arr->size / 4; i ++) {
703 if (lbm_is_ptr(arrdata[i]) &&
704 !((arrdata[i] & LBM_CONTINUATION_INTERNAL0xF8000001u) == LBM_CONTINUATION_INTERNAL0xF8000001u)) {
705 if (!lbm_push (s, arrdata[i])) {
706 lbm_critical_error();
707 }
708 }
709 }
710 }
711 if (lbm_is_ptr(cell->cdr)) {
712 if (!lbm_push(s, cell->cdr)) {
713 lbm_critical_error();
714 break;
715 }
716 }
717 curr = cell->car;
718 goto mark_shortcut; // Skip a push/pop
719 }
720}
721#endif
722
723//Environments are proper lists with a 2 element list stored in each car.
724void lbm_gc_mark_env(lbm_value env) {
725 lbm_value curr = env;
726 lbm_cons_t *c;
727
728 while (lbm_is_ptr(curr)) {
729 c = lbm_ref_cell(curr);
730 c->cdr = lbm_set_gc_mark(c->cdr); // mark the environent list structure.
731 lbm_cons_t *b = lbm_ref_cell(c->car);
732 b->cdr = lbm_set_gc_mark(b->cdr); // mark the binding list head cell.
733 lbm_gc_mark_phase(b->cdr); // mark the bound object.
734 lbm_heap_state.gc_marked +=2;
735 curr = c->cdr;
736 }
737}
738
739
740void lbm_gc_mark_aux(lbm_uint *aux_data, lbm_uint aux_size) {
741 for (lbm_uint i = 0; i < aux_size; i ++) {
742 if (lbm_is_ptr(aux_data[i])) {
743 lbm_type pt_t = lbm_type_of(aux_data[i]);
744 lbm_uint pt_v = lbm_dec_ptr(aux_data[i]);
745 if( pt_t >= LBM_POINTER_TYPE_FIRST0x10000000u &&
746 pt_t <= LBM_POINTER_TYPE_LAST0xAC000000u &&
747 pt_v < lbm_heap_state.heap_size) {
748 lbm_gc_mark_phase(aux_data[i]);
749 }
750 }
751 }
752}
753
754void lbm_gc_mark_roots(lbm_uint *roots, lbm_uint num_roots) {
755 for (lbm_uint i = 0; i < num_roots; i ++) {
1
Assuming 'i' is < 'num_roots'
2
Loop condition is true. Entering loop body
756 lbm_gc_mark_phase(roots[i]);
3
Calling 'lbm_gc_mark_phase'
757 }
758}
759
760// Sweep moves non-marked heap objects to the free list.
761int lbm_gc_sweep_phase(void) {
762 unsigned int i = 0;
763 lbm_cons_t *heap = (lbm_cons_t *)lbm_heap_state.heap;
764
765 for (i = 0; i < lbm_heap_state.heap_size; i ++) {
766 if ( lbm_get_gc_mark(heap[i].cdr)) {
767 heap[i].cdr = lbm_clr_gc_mark(heap[i].cdr);
768 } else {
769 // Check if this cell is a pointer to an array
770 // and free it.
771 if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL0x00000000u) {
772 switch(lbm_dec_sym(heap[i].cdr)) {
773
774 case SYM_IND_I_TYPE0x34: /* fall through */
775 case SYM_IND_U_TYPE0x35:
776 case SYM_IND_F_TYPE0x36:
777 lbm_memory_free((lbm_uint*)heap[i].car);
778 break;
779 case SYM_ARRAY_TYPE0x30:{
780 lbm_array_header_t *arr = (lbm_array_header_t*)heap[i].car;
781 if (lbm_memory_ptr_inside((lbm_uint*)arr->data)) {
782 lbm_memory_free((lbm_uint *)arr->data);
783 lbm_heap_state.gc_recovered_arrays++;
784 }
785 lbm_memory_free((lbm_uint *)arr);
786 } break;
787 case SYM_CHANNEL_TYPE0x37:{
788 lbm_char_channel_t *chan = (lbm_char_channel_t*)heap[i].car;
789 if (lbm_memory_ptr_inside((lbm_uint*)chan)) {
790 lbm_memory_free((lbm_uint*)chan->state);
791 lbm_memory_free((lbm_uint*)chan);
792 }
793 } break;
794 case SYM_CUSTOM_TYPE0x38: {
795 lbm_uint *t = (lbm_uint*)heap[i].car;
796 lbm_custom_type_destroy(t);
797 lbm_memory_free(t);
798 } break;
799 default:
800 break;
801 }
802 }
803 // create pointer to use as new freelist
804 lbm_uint addr = lbm_enc_cons_ptr(i);
805
806 // Clear the "freed" cell.
807 heap[i].car = ENC_SYM_RECOVERED(((0x28) << 4) | 0x00000000u);
808 heap[i].cdr = lbm_heap_state.freelist;
809 lbm_heap_state.freelist = addr;
810 lbm_heap_state.num_alloc --;
811 lbm_heap_state.gc_recovered ++;
812 }
813 }
814 return 1;
815}
816
817void lbm_gc_state_inc(void) {
818 lbm_heap_state.gc_num ++;
819 lbm_heap_state.gc_recovered = 0;
820 lbm_heap_state.gc_marked = 0;
821}
822
823// construct, alter and break apart
824lbm_value lbm_cons(lbm_value car, lbm_value cdr) {
825 return lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, car, cdr);
826}
827
828lbm_value lbm_car(lbm_value c){
829
830 if (lbm_is_ptr(c) ){
19
Assuming the condition is false
831 lbm_cons_t *cell = lbm_ref_cell(c);
832 return cell->car;
833 }
834
835 if (lbm_type_of(c) == LBM_TYPE_SYMBOL0x00000000u &&
20
Assuming the condition is true
22
Taking true branch
836 lbm_dec_sym(c) == SYM_NIL0x0) {
21
Assuming the condition is true
837 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // if nil, return nil.
23
Returning zero
838 }
839
840 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
841}
842
843lbm_value lbm_caar(lbm_value c) {
844
845 lbm_value tmp;
846
847 if (lbm_is_ptr(c)) {
848 tmp = lbm_ref_cell(c)->car;
849
850 if (lbm_is_ptr(tmp)) {
851 return lbm_ref_cell(tmp)->car;
852 } else if (lbm_is_symbol(tmp) && lbm_dec_sym(tmp) == SYM_NIL0x0) {
853 return tmp;
854 }
855 } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL0x0) {
856 return c;
857 }
858 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
859}
860
861
862lbm_value lbm_cadr(lbm_value c) {
863
864 lbm_value tmp;
865
866 if (lbm_is_ptr(c)) {
867 tmp = lbm_ref_cell(c)->cdr;
868
869 if (lbm_is_ptr(tmp)) {
870 return lbm_ref_cell(tmp)->car;
871 } else if (lbm_is_symbol(tmp) && lbm_dec_sym(tmp) == SYM_NIL0x0) {
872 return tmp;
873 }
874 } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL0x0) {
875 return c;
876 }
877 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
878}
879
880lbm_value lbm_cdr(lbm_value c){
881
882 if (lbm_type_of(c) == LBM_TYPE_SYMBOL0x00000000u &&
883 lbm_dec_sym(c) == SYM_NIL0x0) {
884 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // if nil, return nil.
885 }
886
887 if (lbm_is_ptr(c)) {
888 lbm_cons_t *cell = lbm_ref_cell(c);
889 return cell->cdr;
890 }
891 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
892}
893
894lbm_value lbm_cddr(lbm_value c) {
895
896 if (lbm_is_ptr(c)) {
897 lbm_value tmp = lbm_ref_cell(c)->cdr;
898 if (lbm_is_ptr(tmp)) {
899 return lbm_ref_cell(tmp)->cdr;
900 }
901 }
902 if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL0x0) {
903 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
904 }
905 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
906}
907
908int lbm_set_car(lbm_value c, lbm_value v) {
909 int r = 0;
910
911 if (lbm_type_of(c) == LBM_TYPE_CONS0x10000000u) {
912 lbm_cons_t *cell = lbm_ref_cell(c);
913 cell->car = v;
914 r = 1;
915 }
916 return r;
917}
918
919int lbm_set_cdr(lbm_value c, lbm_value v) {
920 int r = 0;
921 if (lbm_is_cons_rw(c)){
922 lbm_cons_t *cell = lbm_ref_cell(c);
923 cell->cdr = v;
924 r = 1;
925 }
926 return r;
927}
928
929int lbm_set_car_and_cdr(lbm_value c, lbm_value car_val, lbm_value cdr_val) {
930 int r = 0;
931 if (lbm_is_cons_rw(c)) {
932 lbm_cons_t *cell = lbm_ref_cell(c);
933 cell->car = car_val;
934 cell->cdr = cdr_val;
935 r = 1;
936 }
937 return r;
938}
939
940/* calculate length of a proper list */
941lbm_uint lbm_list_length(lbm_value c) {
942 lbm_uint len = 0;
943
944 while (lbm_is_cons(c)){
945 len ++;
946 c = lbm_cdr(c);
947 }
948 return len;
949}
950
951/* calculate the length of a list and check that each element
952 fullfills the predicate pred */
953unsigned int lbm_list_length_pred(lbm_value c, bool_Bool *pres, bool_Bool (*pred)(lbm_value)) {
954 bool_Bool res = true1;
955 unsigned int len = 0;
956
957 while (lbm_is_cons(c)){
958 len ++;
959 res = res && pred(lbm_car(c));
960 c = lbm_cdr(c);
961 }
962 *pres = res;
963 return len;
964}
965
966/* reverse a proper list */
967lbm_value lbm_list_reverse(lbm_value list) {
968 if (lbm_type_of(list) == LBM_TYPE_SYMBOL0x00000000u) {
969 return list;
970 }
971
972 lbm_value curr = list;
973
974 lbm_value new_list = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
975 while (lbm_is_cons(curr)) {
976
977 new_list = lbm_cons(lbm_car(curr), new_list);
978 if (lbm_type_of(new_list) == LBM_TYPE_SYMBOL0x00000000u) {
979 return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
980 }
981 curr = lbm_cdr(curr);
982 }
983 return new_list;
984}
985
986lbm_value lbm_list_destructive_reverse(lbm_value list) {
987 if (lbm_type_of(list) == LBM_TYPE_SYMBOL0x00000000u) {
988 return list;
989 }
990 lbm_value curr = list;
991 lbm_value last_cell = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
992
993 while (lbm_is_cons_rw(curr)) {
994 lbm_value next = lbm_cdr(curr);
995 lbm_set_cdr(curr, last_cell);
996 last_cell = curr;
997 curr = next;
998 }
999 return last_cell;
1000}
1001
1002
1003lbm_value lbm_list_copy(int *m, lbm_value list) {
1004 lbm_value curr = list;
1005 lbm_uint n = lbm_list_length(list);
1006 lbm_uint copy_n = n;
1007 if (*m >= 0 && (lbm_uint)*m < n) {
1008 copy_n = (lbm_uint)*m;
1009 } else if (*m == -1) {
1010 *m = (int)n; // TODO: smaller range in target variable.
1011 }
1012 if (copy_n == 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1013 lbm_uint new_list = lbm_heap_allocate_list(copy_n);
1014 if (lbm_is_symbol(new_list)) return new_list;
1015 lbm_value curr_targ = new_list;
1016
1017 while (lbm_is_cons(curr) && copy_n > 0) {
1018 lbm_value v = lbm_car(curr);
1019 lbm_set_car(curr_targ, v);
1020 curr_targ = lbm_cdr(curr_targ);
1021 curr = lbm_cdr(curr);
1022 copy_n --;
1023 }
1024
1025 return new_list;
1026}
1027
1028// Append for proper lists only
1029// Destructive update of list1.
1030lbm_value lbm_list_append(lbm_value list1, lbm_value list2) {
1031
1032 if(lbm_is_list_rw(list1) &&
1033 lbm_is_list(list2)) {
1034
1035 lbm_value curr = list1;
1036 while(lbm_type_of(lbm_cdr(curr)) == LBM_TYPE_CONS0x10000000u) {
1037 curr = lbm_cdr(curr);
1038 }
1039 if (lbm_is_symbol_nil(curr)) return list2;
1040 lbm_set_cdr(curr, list2);
1041 return list1;
1042 }
1043 return ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u);
1044}
1045
1046lbm_value lbm_list_drop(unsigned int n, lbm_value ls) {
1047 lbm_value curr = ls;
1048 while (lbm_type_of_functional(curr) == LBM_TYPE_CONS0x10000000u &&
1049 n > 0) {
1050 curr = lbm_cdr(curr);
1051 n --;
1052 }
1053 return curr;
1054}
1055
1056lbm_value lbm_index_list(lbm_value l, int32_t n) {
1057 lbm_value curr = l;
1058
1059 if (n < 0) {
1060 int32_t len = (int32_t)lbm_list_length(l);
1061 n = len + n;
1062 if (n < 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1063 }
1064
1065 while (lbm_is_cons(curr) &&
1066 n > 0) {
1067 curr = lbm_cdr(curr);
1068 n --;
1069 }
1070 if (lbm_is_cons(curr)) {
1071 return lbm_car(curr);
1072 } else {
1073 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1074 }
1075}
1076
1077
1078
1079// Arrays are part of the heap module because their lifespan is managed
1080// by the garbage collector. The data in the array is not stored
1081// in the "heap of cons cells".
1082int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){
1083
1084 lbm_array_header_t *array = NULL((void*)0);
1085
1086 array = (lbm_array_header_t*)lbm_memory_allocate(sizeof(lbm_array_header_t) / sizeof(lbm_uint));
1087
1088 if (array == NULL((void*)0)) {
1089 *res = ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
1090 return 0;
1091 }
1092
1093 array->data = (lbm_uint*)lbm_malloc(size);
1094
1095 if (array->data == NULL((void*)0)) {
1096 lbm_memory_free((lbm_uint*)array);
1097 *res = ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
1098 return 0;
1099 }
1100 memset(array->data, 0, size);
1101 array->size = size;
1102
1103 // allocating a cell for array's heap-presence
1104 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_ARRAY0x80000000u, (lbm_uint) array, ENC_SYM_ARRAY_TYPE(((0x30) << 4) | 0x00000000u));
1105
1106 *res = cell;
1107
1108 if (lbm_type_of(cell) == LBM_TYPE_SYMBOL0x00000000u) { // Out of heap memory
1109 lbm_memory_free((lbm_uint*)array->data);
1110 lbm_memory_free((lbm_uint*)array);
1111 return 0;
1112 }
1113
1114 lbm_heap_state.num_alloc_arrays ++;
1115
1116 return 1;
1117}
1118
1119// Convert a C array into an lbm_array.
1120// if the array is in LBM_MEMORY, the lifetime will be managed by the GC.
1121int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) {
1122
1123 lbm_array_header_t *array = NULL((void*)0);
1124 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_ARRAY_TYPE(((0x30) << 4) | 0x00000000u));
1125
1126 if (lbm_type_of(cell) == LBM_TYPE_SYMBOL0x00000000u) { // Out of heap memory
1127 *value = cell;
1128 return 0;
1129 }
1130
1131 array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t));
1132
1133 if (array == NULL((void*)0)) {
1134 *value = ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
1135 return 0;
1136 }
1137
1138 array->data = (lbm_uint*)data;
1139 array->size = num_elt;
1140
1141 lbm_set_car(cell, (lbm_uint)array);
1142
1143 cell = lbm_set_ptr_type(cell, LBM_TYPE_ARRAY0x80000000u);
1144 *value = cell;
1145 return 1;
1146}
1147
1148lbm_int lbm_heap_array_get_size(lbm_value arr) {
1149
1150 lbm_int r = -1;
1151 if (lbm_is_array_r(arr)) {
1152 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1153 if (header == NULL((void*)0)) {
1154 return r;
1155 }
1156 r = (lbm_int)header->size;
1157 }
1158 return r;
1159}
1160
1161const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) {
1162 uint8_t *r = NULL((void*)0);
1163 if (lbm_is_array_r(arr)) {
1164 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1165 if (header == NULL((void*)0)) {
1166 return r;
1167 }
1168 r = (uint8_t*)header->data;
1169 }
1170 return r;
1171}
1172
1173uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) {
1174 uint8_t *r = NULL((void*)0);
1175 if (lbm_is_array_rw(arr)) {
1176 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1177 if (header == NULL((void*)0)) {
1178 return r;
1179 }
1180 r = (uint8_t*)header->data;
1181 }
1182 return r;
1183}
1184
1185
1186/* Explicitly freeing an array.
1187
1188 This is a highly unsafe operation and can only be safely
1189 used if the heap cell that points to the array has not been made
1190 accessible to the program.
1191
1192 So This function can be used to free an array in case an array
1193 is being constructed and some error case appears while doing so
1194 If the array still have not become available it can safely be
1195 "explicitly" freed.
1196
1197 The problem is that if the "array" heap-cell is made available to
1198 the program, this cell can easily be duplicated and we would have
1199 to search the entire heap to find all cells pointing to the array
1200 memory in question and "null"-them out before freeing the memory
1201*/
1202
1203int lbm_heap_explicit_free_array(lbm_value arr) {
1204
1205 int r = 0;
1206 if (lbm_is_array_rw(arr)) {
1207
1208 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1209 if (header == NULL((void*)0)) {
1210 return 0;
1211 }
1212 lbm_memory_free((lbm_uint*)header->data);
1213 lbm_memory_free((lbm_uint*)header);
1214
1215 arr = lbm_set_ptr_type(arr, LBM_TYPE_CONS0x10000000u);
1216 lbm_set_car(arr, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1217 lbm_set_cdr(arr, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1218 r = 1;
1219 }
1220
1221 return r;
1222}
1223
1224lbm_uint lbm_size_of(lbm_type t) {
1225 lbm_uint s = 0;
1226 switch(t) {
1227 case LBM_TYPE_BYTE0x00000004u:
1228 s = 1;
1229 break;
1230 case LBM_TYPE_I0x00000008u: /* fall through */
1231 case LBM_TYPE_U0x0000000Cu:
1232 case LBM_TYPE_SYMBOL0x00000000u:
1233 s = sizeof(lbm_uint);
1234 break;
1235 case LBM_TYPE_I320x28000000u: /* fall through */
1236 case LBM_TYPE_U320x38000000u:
1237 case LBM_TYPE_FLOAT0x68000000u:
1238 s = 4;
1239 break;
1240 case LBM_TYPE_I640x48000000u: /* fall through */
1241 case LBM_TYPE_U640x58000000u:
1242 case LBM_TYPE_DOUBLE0x78000000u:
1243 s = 8;
1244 break;
1245 }
1246 return s;
1247}
1248
1249static bool_Bool dummy_flash_write(lbm_uint ix, lbm_uint val) {
1250 (void)ix;
1251 (void)val;
1252 return false0;
1253}
1254
1255static const_heap_write_fun const_heap_write = dummy_flash_write;
1256
1257int lbm_const_heap_init(const_heap_write_fun w_fun,
1258 lbm_const_heap_t *heap,
1259 lbm_uint *addr,
1260 lbm_uint num_words) {
1261 if (((uintptr_t)addr % 4) != 0) return 0;
1262 if ((num_words % 2) != 0) return 0;
1263
1264 if (!lbm_const_heap_mutex_initialized) {
1265 mutex_init(&lbm_const_heap_mutex);
1266 lbm_const_heap_mutex_initialized = true1;
1267 }
1268
1269 if (!lbm_mark_mutex_initialized) {
1270 mutex_init(&lbm_mark_mutex);
1271 lbm_mark_mutex_initialized = true1;
1272 }
1273
1274 const_heap_write = w_fun;
1275
1276 heap->heap = addr;
1277 heap->size = num_words;
1278 heap->next = 0;
1279
1280 lbm_const_heap_state = heap;
1281 // ref_cell views the lbm_uint array as an lbm_cons_t array
1282 lbm_heaps[1] = (lbm_cons_t*)addr;
1283 return 1;
1284}
1285
1286lbm_flash_status lbm_allocate_const_cell(lbm_value *res) {
1287 lbm_flash_status r = LBM_FLASH_FULL;
1288
1289 mutex_lock(&lbm_const_heap_mutex);
1290 // waste a cell if we have ended up unaligned after writing an array to flash.
1291 if (lbm_const_heap_state->next % 2 == 1) {
1292 lbm_const_heap_state->next++;
1293 }
1294
1295 if (lbm_const_heap_state &&
1296 (lbm_const_heap_state->next+1) < lbm_const_heap_state->size) {
1297 // A cons cell uses two words.
1298 lbm_value cell = lbm_const_heap_state->next;
1299 lbm_const_heap_state->next += 2;
1300 *res = (cell << LBM_ADDRESS_SHIFT2) | LBM_PTR_BIT0x00000001u | LBM_TYPE_CONS0x10000000u | LBM_PTR_TO_CONSTANT_BIT0x04000000u;
1301 r = LBM_FLASH_WRITE_OK;
1302 }
1303 mutex_unlock(&lbm_const_heap_mutex);
1304 return r;
1305}
1306
1307lbm_flash_status lbm_write_const_raw(lbm_uint *data, lbm_uint n, lbm_uint *res) {
1308
1309 lbm_flash_status r = LBM_FLASH_FULL;
1310
1311 if (lbm_const_heap_state &&
1312 (lbm_const_heap_state->next + n) < lbm_const_heap_state->size) {
1313 lbm_uint ix = lbm_const_heap_state->next;
1314
1315 for (unsigned int i = 0; i < n; i ++) {
1316 if (!const_heap_write(ix + i, ((lbm_uint*)data)[i]))
1317 return LBM_FLASH_WRITE_ERROR;
1318 }
1319 lbm_const_heap_state->next += n;
1320 *res = (lbm_uint)&lbm_const_heap_state->heap[ix];
1321 r = LBM_FLASH_WRITE_OK;
1322 }
1323 return r;
1324}
1325
1326lbm_flash_status write_const_cdr(lbm_value cell, lbm_value val) {
1327 lbm_uint addr = lbm_dec_ptr(cell);
1328 if (const_heap_write(addr+1, val))
1329 return LBM_FLASH_WRITE_OK;
1330 return LBM_FLASH_WRITE_ERROR;
1331}
1332
1333lbm_flash_status write_const_car(lbm_value cell, lbm_value val) {
1334 lbm_uint addr = lbm_dec_ptr(cell);
1335 if (const_heap_write(addr, val))
1336 return LBM_FLASH_WRITE_OK;
1337 return LBM_FLASH_WRITE_ERROR;
1338}
1339
1340lbm_uint lbm_flash_memory_usage(void) {
1341 return lbm_const_heap_state->next;
1342}

./include/stack.h

1/** \file stack.h */
2/*
3 Copyright 2019 Joel Svensson svenssonjoel@yahoo.se
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#ifndef STACK_H_
19#define STACK_H_
20
21
22#include <stdlib.h>
23#include <stdint.h>
24#include <stdbool.h>
25#include <stdio.h>
26
27#include "lbm_types.h"
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33typedef struct {
34 lbm_uint* data;
35 lbm_uint sp;
36 lbm_uint size;
37 lbm_uint max_sp;
38} lbm_stack_t;
39
40/** Allocate a stack on the symbols and arrays memory.
41 * lbm_memory_init must have been run before this function or it will fail.
42 * \param s Pointer to an lbm_stack_t to initialize.
43 * \param stack_size Size in 32 bit words of stack to allocate.
44 * \return 1 on success and 0 on failure.
45 */
46int lbm_stack_allocate(lbm_stack_t *s, lbm_uint stack_size);
47/** Create a stack in a statically allocated array.
48 *
49 * \param s Pointer to an lbm_stack_t to initialize.
50 * \param data Pointer to array of 32 bit words to use as the stack storage.
51 * \param size Size in number of 32 bit words.
52 * \return 1
53 */
54int lbm_stack_create(lbm_stack_t *s, lbm_uint* data, lbm_uint size);
55/** Free a stack allocated on the lispbm_memory.
56 *
57 * \param s Pointer to lbm_stack_t to free.
58 */
59void lbm_stack_free(lbm_stack_t *s);
60/** Sets the stack SP to 0.
61 *
62 * \param s Stack to clear.
63 */
64void lbm_stack_clear(lbm_stack_t *s);
65/** Get a pointer to the nth element (from the top) of a stack.
66 *
67 * \param s Stack.
68 * \param n Index.
69 * \return Pointer into the stack or NULL.
70 */
71lbm_uint *lbm_get_stack_ptr(lbm_stack_t *s, lbm_uint n);
72/** Drop n elements (from the top) of a stack.
73 *
74 * \param s Stack to drop elements from.
75 * \param n Number of elements to drop.
76 * \return 1 on Success and 0 on failure.
77 */
78int lbm_stack_drop(lbm_stack_t *s, lbm_uint n);
79
80/** Reserve place for n elements on the stack and
81 * move the stack pointer to the new top.
82 * \param s Stack to reserve values on
83 * \param n Number of values to reserve
84 * \return Pointer into stack position of reserver value 0 or NULL
85 * on failure
86 */
87lbm_uint *lbm_stack_reserve(lbm_stack_t *s, lbm_uint n);
88/** Push an element onto a stack.
89 *
90 * \param s Stack to push a value onto.
91 * \param val Value to push to the stack.
92 * \return 1 on success and 0 on failure (stack is full).
93 */
94int lbm_push(lbm_stack_t *s, lbm_uint val);
95/** Pop a value from a stack.
96 *
97 * \param s Stack to pop a value from.
98 * \param val Pointer to an lbm_value to store the pop:ed value int.
99 * \return 1 on success and 0 on failure (stack is empty).
100 */
101int lbm_pop(lbm_stack_t *s, lbm_uint *val);
102
103/** Check if a stack is empty.
104 *
105 * \param s Stack to check.
106 * \return 1 if stack is empty otherwise 0.
107 */
108static inline int lbm_stack_is_empty(lbm_stack_t *s) {
109 if (s->sp == 0) return 1;
5
Assuming field 'sp' is not equal to 0
6
Taking false branch
110 return 0;
7
Returning zero, which participates in a condition later
111}
112
113/** Push 2 values to a stack.
114 *
115 * \param s Stack to push values onto.
116 * \param val0 Is pushed first.
117 * \param val1 Is pushed last.
118 * \return 1 on success and 0 on failure (stack is full).
119 */
120int lbm_push_2(lbm_stack_t *s, lbm_uint val0, lbm_uint val1);
121
122/** Pop 2 values from a stack.
123 *
124 * \param s Stack to pop values from.
125 * \param r0 Pointer to lbm_value where the first pop:ed value will be stored.
126 * \param r1 Pointer to lbm_value where the seconds pop:ed value will be stored.
127 * \return 1 on success and 0 on failure (stack is empty).
128 */
129int lbm_pop_2(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1);
130
131/** Pop 3 values from a stack.
132 *
133 * \param s Stack to pop values from.
134 * \param r0
135 * \param r1
136 * \param r2
137 * \return 1 on success and 0 on failure (stack is empty).
138 */
139int lbm_pop_3(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1, lbm_uint *r2);
140
141#ifdef __cplusplus
142}
143#endif
144#endif