Bug Summary

File:heap.c
Warning:line 713, 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.23.0/scan-build/2024-03-09-191247-1858527-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
517 lbm_value res;
518
519 // it is a ptr replace freelist with cdr of freelist;
520 res = lbm_heap_state.freelist;
521
522 if (lbm_type_of(res) == LBM_TYPE_CONS0x10000000u) {
523 lbm_uint heap_ix = lbm_dec_ptr(res);
524 //lbm_cons_t *rc = lbm_ref_cell(res);
525 lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr;
526
527 lbm_heap_state.num_alloc++;
528
529 lbm_heap_state.heap[heap_ix].car = car;
530 lbm_heap_state.heap[heap_ix].cdr = cdr;
531 res = lbm_set_ptr_type(res, ptr_type);
532 return res;
533 }
534 else if ((lbm_type_of(res) == LBM_TYPE_SYMBOL0x00000000u) &&
535 (lbm_dec_sym(res) == SYM_NIL0x0)) {
536 // all is as it should be (but no free cells)
537 return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
538 }
539 // Unreachable, unless something very wrong
540 return ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u);
541}
542
543lbm_value lbm_heap_allocate_list(lbm_uint n) {
544 if (n == 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
545 if (lbm_heap_num_free() < n) return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
546
547 lbm_value curr = lbm_heap_state.freelist;
548 lbm_value res = curr;
549 if (lbm_type_of(curr) == LBM_TYPE_CONS0x10000000u) {
550
551 lbm_cons_t *c_cell = NULL((void*)0);
552 lbm_uint count = 0;
553 do {
554 c_cell = lbm_ref_cell(curr);
555 c_cell->car = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
556 curr = c_cell->cdr;
557 count ++;
558 } while (count < n);
559 lbm_heap_state.freelist = curr;
560 c_cell->cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
561 lbm_heap_state.num_alloc+=count;
562 return res;
563 }
564 return ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u);
565}
566
567lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) {
568 if (n == 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
569 if (lbm_heap_num_free() < n) return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
570
571 lbm_value curr = lbm_heap_state.freelist;
572 lbm_value res = curr;
573 if (lbm_type_of(curr) == LBM_TYPE_CONS0x10000000u) {
574
575 lbm_cons_t *c_cell = NULL((void*)0);
576 unsigned int count = 0;
577 do {
578 c_cell = lbm_ref_cell(curr);
579 c_cell->car = va_arg(valist, lbm_value)__builtin_va_arg(valist, lbm_value);
580 curr = c_cell->cdr;
581 count ++;
582 } while (count < n);
583 lbm_heap_state.freelist = curr;
584 c_cell->cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
585 lbm_heap_state.num_alloc+=count;
586 return res;
587 }
588 return ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u);
589}
590
591lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) {
592 va_list valist;
593 va_start(valist, n)__builtin_va_start(valist, n);
594 lbm_value r = lbm_heap_allocate_list_init_va(n, valist);
595 va_end(valist)__builtin_va_end(valist);
596 return r;
597}
598
599lbm_uint lbm_heap_num_allocated(void) {
600 return lbm_heap_state.num_alloc;
601}
602lbm_uint lbm_heap_size(void) {
603 return lbm_heap_state.heap_size;
604}
605
606lbm_uint lbm_heap_size_bytes(void) {
607 return lbm_heap_state.heap_bytes;
608}
609
610void lbm_get_heap_state(lbm_heap_state_t *res) {
611 *res = lbm_heap_state;
612}
613
614lbm_uint lbm_get_gc_stack_max(void) {
615 return lbm_heap_state.gc_stack.max_sp;
616}
617
618lbm_uint lbm_get_gc_stack_size(void) {
619 return lbm_heap_state.gc_stack.size;
620}
621
622#ifdef USE_GC_PTR_REV
623static inline void value_assign(lbm_value *a, lbm_value b) {
624 lbm_value a_old = *a & LBM_GC_MASK0x00000002u;
625 *a = a_old | (b & ~LBM_GC_MASK0x00000002u);
626}
627
628void lbm_gc_mark_phase(lbm_value root) {
629 bool_Bool work_to_do = true1;
630
631 if (!lbm_is_ptr(root)) return;
632
633 mutex_lock(&lbm_const_heap_mutex);
634 lbm_value curr = root;
635 lbm_value prev = lbm_enc_cons_ptr(LBM_PTR_NULL(0x03FFFFFCu >> 2));
636
637 while (work_to_do) {
638 // follow leftwards pointers
639 while (lbm_is_ptr(curr) &&
640 (lbm_dec_ptr(curr) != LBM_PTR_NULL(0x03FFFFFCu >> 2)) &&
641 ((curr & LBM_PTR_TO_CONSTANT_BIT0x04000000u) == 0) &&
642 !lbm_get_gc_mark(lbm_cdr(curr))) {
643 // Mark the cell if not a constant cell
644 lbm_cons_t *cell = lbm_ref_cell(curr);
645 cell->cdr = lbm_set_gc_mark(cell->cdr);
646 if (lbm_is_cons_rw(curr)) {
647 lbm_value next = 0;
648 value_assign(&next, cell->car);
649 value_assign(&cell->car, prev);
650 value_assign(&prev,curr);
651 value_assign(&curr, next);
652 }
653 // Will jump out next iteration as gc mark is set in curr.
654 }
655 while (lbm_is_ptr(prev) &&
656 (lbm_dec_ptr(prev) != LBM_PTR_NULL(0x03FFFFFCu >> 2)) &&
657 lbm_get_gc_flag(lbm_car(prev)) ) {
658 // clear the flag
659 lbm_cons_t *cell = lbm_ref_cell(prev);
660 cell->car = lbm_clr_gc_flag(cell->car);
661 lbm_value next = 0;
662 value_assign(&next, cell->cdr);
663 value_assign(&cell->cdr, curr);
664 value_assign(&curr, prev);
665 value_assign(&prev, next);
666 }
667 if (lbm_is_ptr(prev) &&
668 lbm_dec_ptr(prev) == LBM_PTR_NULL(0x03FFFFFCu >> 2)) {
669 work_to_do = false0;
670 } else if (lbm_is_ptr(prev)) {
671 // set the flag
672 lbm_cons_t *cell = lbm_ref_cell(prev);
673 cell->car = lbm_set_gc_flag(cell->car);
674 lbm_value next = 0;
675 value_assign(&next, cell->car);
676 value_assign(&cell->car, curr);
677 value_assign(&curr, cell->cdr);
678 value_assign(&cell->cdr, next);
679 }
680 }
681 mutex_unlock(&lbm_const_heap_mutex);
682}
683
684#else
685extern eval_context_t *ctx_running;
686void lbm_gc_mark_phase(lbm_value root) {
687
688 lbm_stack_t *s = &lbm_heap_state.gc_stack;
689 s->data[s->sp++] = root;
690
691 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
692 lbm_value curr;
693 lbm_pop(s, &curr);
694
695 mark_shortcut:
696 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
697 continue;
698 }
699
700 lbm_cons_t *cell = &lbm_heap_state.heap[lbm_dec_ptr(curr)];
701
702 if (lbm_get_gc_mark(cell->cdr)) continue;
13
Assuming the condition is false
14
Taking false branch
703 cell->cdr = lbm_set_gc_mark(cell->cdr);
704 lbm_heap_state.gc_marked ++;
705
706 lbm_value t_ptr = lbm_type_of(curr);
707
708 if (t_ptr >= LBM_NON_CONS_POINTER_TYPE_FIRST0x20000000u &&
15
Assuming 't_ptr' is < LBM_NON_CONS_POINTER_TYPE_FIRST
709 t_ptr <= LBM_NON_CONS_POINTER_TYPE_LAST0xAC000000u) continue;
710
711 if (cell->car == ENC_SYM_CONT(((0x10E) << 4) | 0x00000000u)) {
16
Assuming the condition is true
17
Taking true branch
712 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
713 lbm_value *arrdata = (lbm_value *)arr->data;
26
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'arr')
714 for (lbm_uint i = 0; i < arr->size / 4; i ++) {
715 if (lbm_is_ptr(arrdata[i]) &&
716 !((arrdata[i] & LBM_CONTINUATION_INTERNAL0xF8000001u) == LBM_CONTINUATION_INTERNAL0xF8000001u)) {
717 if (!lbm_push (s, arrdata[i])) {
718 lbm_critical_error();
719 }
720 }
721 }
722 }
723 if (lbm_is_ptr(cell->cdr)) {
724 if (!lbm_push(s, cell->cdr)) {
725 lbm_critical_error();
726 break;
727 }
728 }
729 curr = cell->car;
730 goto mark_shortcut; // Skip a push/pop
731 }
732}
733#endif
734
735//Environments are proper lists with a 2 element list stored in each car.
736void lbm_gc_mark_env(lbm_value env) {
737 lbm_value curr = env;
738 lbm_cons_t *c;
739
740 while (lbm_is_ptr(curr)) {
741 c = lbm_ref_cell(curr);
742 c->cdr = lbm_set_gc_mark(c->cdr); // mark the environent list structure.
743 lbm_cons_t *b = lbm_ref_cell(c->car);
744 b->cdr = lbm_set_gc_mark(b->cdr); // mark the binding list head cell.
745 lbm_gc_mark_phase(b->cdr); // mark the bound object.
746 lbm_heap_state.gc_marked +=2;
747 curr = c->cdr;
748 }
749}
750
751
752void lbm_gc_mark_aux(lbm_uint *aux_data, lbm_uint aux_size) {
753 for (lbm_uint i = 0; i < aux_size; i ++) {
754 if (lbm_is_ptr(aux_data[i])) {
755 lbm_type pt_t = lbm_type_of(aux_data[i]);
756 lbm_uint pt_v = lbm_dec_ptr(aux_data[i]);
757 if( pt_t >= LBM_POINTER_TYPE_FIRST0x10000000u &&
758 pt_t <= LBM_POINTER_TYPE_LAST0xAC000000u &&
759 pt_v < lbm_heap_state.heap_size) {
760 lbm_gc_mark_phase(aux_data[i]);
761 }
762 }
763 }
764}
765
766void lbm_gc_mark_roots(lbm_uint *roots, lbm_uint num_roots) {
767 for (lbm_uint i = 0; i < num_roots; i ++) {
1
Assuming 'i' is < 'num_roots'
2
Loop condition is true. Entering loop body
768 lbm_gc_mark_phase(roots[i]);
3
Calling 'lbm_gc_mark_phase'
769 }
770}
771
772// Sweep moves non-marked heap objects to the free list.
773int lbm_gc_sweep_phase(void) {
774 unsigned int i = 0;
775 lbm_cons_t *heap = (lbm_cons_t *)lbm_heap_state.heap;
776
777 for (i = 0; i < lbm_heap_state.heap_size; i ++) {
778 if ( lbm_get_gc_mark(heap[i].cdr)) {
779 heap[i].cdr = lbm_clr_gc_mark(heap[i].cdr);
780 } else {
781 // Check if this cell is a pointer to an array
782 // and free it.
783 if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL0x00000000u) {
784 switch(lbm_dec_sym(heap[i].cdr)) {
785
786 case SYM_IND_I_TYPE0x34: /* fall through */
787 case SYM_IND_U_TYPE0x35:
788 case SYM_IND_F_TYPE0x36:
789 lbm_memory_free((lbm_uint*)heap[i].car);
790 break;
791 case SYM_ARRAY_TYPE0x30:{
792 lbm_array_header_t *arr = (lbm_array_header_t*)heap[i].car;
793 if (lbm_memory_ptr_inside((lbm_uint*)arr->data)) {
794 lbm_memory_free((lbm_uint *)arr->data);
795 lbm_heap_state.gc_recovered_arrays++;
796 }
797 lbm_memory_free((lbm_uint *)arr);
798 } break;
799 case SYM_CHANNEL_TYPE0x37:{
800 lbm_char_channel_t *chan = (lbm_char_channel_t*)heap[i].car;
801 if (lbm_memory_ptr_inside((lbm_uint*)chan)) {
802 lbm_memory_free((lbm_uint*)chan->state);
803 lbm_memory_free((lbm_uint*)chan);
804 }
805 } break;
806 case SYM_CUSTOM_TYPE0x38: {
807 lbm_uint *t = (lbm_uint*)heap[i].car;
808 lbm_custom_type_destroy(t);
809 lbm_memory_free(t);
810 } break;
811 default:
812 break;
813 }
814 }
815 // create pointer to use as new freelist
816 lbm_uint addr = lbm_enc_cons_ptr(i);
817
818 // Clear the "freed" cell.
819 heap[i].car = ENC_SYM_RECOVERED(((0x28) << 4) | 0x00000000u);
820 heap[i].cdr = lbm_heap_state.freelist;
821 lbm_heap_state.freelist = addr;
822 lbm_heap_state.num_alloc --;
823 lbm_heap_state.gc_recovered ++;
824 }
825 }
826 return 1;
827}
828
829void lbm_gc_state_inc(void) {
830 lbm_heap_state.gc_num ++;
831 lbm_heap_state.gc_recovered = 0;
832 lbm_heap_state.gc_marked = 0;
833}
834
835// construct, alter and break apart
836lbm_value lbm_cons(lbm_value car, lbm_value cdr) {
837 return lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, car, cdr);
838}
839
840lbm_value lbm_car(lbm_value c){
841
842 if (lbm_is_ptr(c) ){
19
Assuming the condition is false
843 lbm_cons_t *cell = lbm_ref_cell(c);
844 return cell->car;
845 }
846
847 if (lbm_type_of(c) == LBM_TYPE_SYMBOL0x00000000u &&
20
Assuming the condition is true
22
Taking true branch
848 lbm_dec_sym(c) == SYM_NIL0x0) {
21
Assuming the condition is true
849 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // if nil, return nil.
23
Returning zero
850 }
851
852 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
853}
854
855lbm_value lbm_caar(lbm_value c) {
856
857 lbm_value tmp;
858
859 if (lbm_is_ptr(c)) {
860 tmp = lbm_ref_cell(c)->car;
861
862 if (lbm_is_ptr(tmp)) {
863 return lbm_ref_cell(tmp)->car;
864 } else if (lbm_is_symbol(tmp) && lbm_dec_sym(tmp) == SYM_NIL0x0) {
865 return tmp;
866 }
867 } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL0x0) {
868 return c;
869 }
870 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
871}
872
873
874lbm_value lbm_cadr(lbm_value c) {
875
876 lbm_value tmp;
877
878 if (lbm_is_ptr(c)) {
879 tmp = lbm_ref_cell(c)->cdr;
880
881 if (lbm_is_ptr(tmp)) {
882 return lbm_ref_cell(tmp)->car;
883 } else if (lbm_is_symbol(tmp) && lbm_dec_sym(tmp) == SYM_NIL0x0) {
884 return tmp;
885 }
886 } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL0x0) {
887 return c;
888 }
889 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
890}
891
892lbm_value lbm_cdr(lbm_value c){
893
894 if (lbm_type_of(c) == LBM_TYPE_SYMBOL0x00000000u &&
895 lbm_dec_sym(c) == SYM_NIL0x0) {
896 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // if nil, return nil.
897 }
898
899 if (lbm_is_ptr(c)) {
900 lbm_cons_t *cell = lbm_ref_cell(c);
901 return cell->cdr;
902 }
903 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
904}
905
906lbm_value lbm_cddr(lbm_value c) {
907
908 if (lbm_is_ptr(c)) {
909 lbm_value tmp = lbm_ref_cell(c)->cdr;
910 if (lbm_is_ptr(tmp)) {
911 return lbm_ref_cell(tmp)->cdr;
912 }
913 }
914 if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL0x0) {
915 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
916 }
917 return ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u);
918}
919
920int lbm_set_car(lbm_value c, lbm_value v) {
921 int r = 0;
922
923 if (lbm_type_of(c) == LBM_TYPE_CONS0x10000000u) {
924 lbm_cons_t *cell = lbm_ref_cell(c);
925 cell->car = v;
926 r = 1;
927 }
928 return r;
929}
930
931int lbm_set_cdr(lbm_value c, lbm_value v) {
932 int r = 0;
933 if (lbm_is_cons_rw(c)){
934 lbm_cons_t *cell = lbm_ref_cell(c);
935 cell->cdr = v;
936 r = 1;
937 }
938 return r;
939}
940
941int lbm_set_car_and_cdr(lbm_value c, lbm_value car_val, lbm_value cdr_val) {
942 int r = 0;
943 if (lbm_is_cons_rw(c)) {
944 lbm_cons_t *cell = lbm_ref_cell(c);
945 cell->car = car_val;
946 cell->cdr = cdr_val;
947 r = 1;
948 }
949 return r;
950}
951
952/* calculate length of a proper list */
953lbm_uint lbm_list_length(lbm_value c) {
954 lbm_uint len = 0;
955
956 while (lbm_is_cons(c)){
957 len ++;
958 c = lbm_cdr(c);
959 }
960 return len;
961}
962
963/* calculate the length of a list and check that each element
964 fullfills the predicate pred */
965unsigned int lbm_list_length_pred(lbm_value c, bool_Bool *pres, bool_Bool (*pred)(lbm_value)) {
966 bool_Bool res = true1;
967 unsigned int len = 0;
968
969 while (lbm_is_cons(c)){
970 len ++;
971 res = res && pred(lbm_car(c));
972 c = lbm_cdr(c);
973 }
974 *pres = res;
975 return len;
976}
977
978/* reverse a proper list */
979lbm_value lbm_list_reverse(lbm_value list) {
980 if (lbm_type_of(list) == LBM_TYPE_SYMBOL0x00000000u) {
981 return list;
982 }
983
984 lbm_value curr = list;
985
986 lbm_value new_list = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
987 while (lbm_is_cons(curr)) {
988
989 new_list = lbm_cons(lbm_car(curr), new_list);
990 if (lbm_type_of(new_list) == LBM_TYPE_SYMBOL0x00000000u) {
991 return ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
992 }
993 curr = lbm_cdr(curr);
994 }
995 return new_list;
996}
997
998lbm_value lbm_list_destructive_reverse(lbm_value list) {
999 if (lbm_type_of(list) == LBM_TYPE_SYMBOL0x00000000u) {
1000 return list;
1001 }
1002 lbm_value curr = list;
1003 lbm_value last_cell = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1004
1005 while (lbm_is_cons_rw(curr)) {
1006 lbm_value next = lbm_cdr(curr);
1007 lbm_set_cdr(curr, last_cell);
1008 last_cell = curr;
1009 curr = next;
1010 }
1011 return last_cell;
1012}
1013
1014
1015lbm_value lbm_list_copy(int *m, lbm_value list) {
1016 lbm_value curr = list;
1017 lbm_uint n = lbm_list_length(list);
1018 lbm_uint copy_n = n;
1019 if (*m >= 0 && (lbm_uint)*m < n) {
1020 copy_n = (lbm_uint)*m;
1021 } else if (*m == -1) {
1022 *m = (int)n; // TODO: smaller range in target variable.
1023 }
1024 lbm_uint new_list = lbm_heap_allocate_list(copy_n);
1025 if (lbm_is_symbol(new_list)) return new_list;
1026 lbm_value curr_targ = new_list;
1027
1028 while (lbm_is_cons(curr) && copy_n > 0) {
1029 lbm_value v = lbm_car(curr);
1030 lbm_set_car(curr_targ, v);
1031 curr_targ = lbm_cdr(curr_targ);
1032 curr = lbm_cdr(curr);
1033 copy_n --;
1034 }
1035
1036 return new_list;
1037}
1038
1039// Append for proper lists only
1040// Destructive update of list1.
1041lbm_value lbm_list_append(lbm_value list1, lbm_value list2) {
1042
1043 if(lbm_is_list_rw(list1) &&
1044 lbm_is_list(list2)) {
1045
1046 lbm_value curr = list1;
1047 while(lbm_type_of(lbm_cdr(curr)) == LBM_TYPE_CONS0x10000000u) {
1048 curr = lbm_cdr(curr);
1049 }
1050 if (lbm_is_symbol_nil(curr)) return list2;
1051 lbm_set_cdr(curr, list2);
1052 return list1;
1053 }
1054 return ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u);
1055}
1056
1057lbm_value lbm_list_drop(unsigned int n, lbm_value ls) {
1058 lbm_value curr = ls;
1059 while (lbm_type_of_functional(curr) == LBM_TYPE_CONS0x10000000u &&
1060 n > 0) {
1061 curr = lbm_cdr(curr);
1062 n --;
1063 }
1064 return curr;
1065}
1066
1067lbm_value lbm_index_list(lbm_value l, int32_t n) {
1068 lbm_value curr = l;
1069
1070 if (n < 0) {
1071 int32_t len = (int32_t)lbm_list_length(l);
1072 n = len + n;
1073 if (n < 0) return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1074 }
1075
1076 while (lbm_is_cons(curr) &&
1077 n > 0) {
1078 curr = lbm_cdr(curr);
1079 n --;
1080 }
1081 if (lbm_is_cons(curr)) {
1082 return lbm_car(curr);
1083 } else {
1084 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1085 }
1086}
1087
1088
1089
1090// Arrays are part of the heap module because their lifespan is managed
1091// by the garbage collector. The data in the array is not stored
1092// in the "heap of cons cells".
1093int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){
1094
1095 lbm_array_header_t *array = NULL((void*)0);
1096
1097 array = (lbm_array_header_t*)lbm_memory_allocate(sizeof(lbm_array_header_t) / sizeof(lbm_uint));
1098
1099 if (array == NULL((void*)0)) {
1100 *res = ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
1101 return 0;
1102 }
1103
1104 array->data = (lbm_uint*)lbm_malloc(size);
1105
1106 if (array->data == NULL((void*)0)) {
1107 lbm_memory_free((lbm_uint*)array);
1108 *res = ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
1109 return 0;
1110 }
1111 memset(array->data, 0, size);
1112 array->size = size;
1113
1114 // allocating a cell for array's heap-presence
1115 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_ARRAY0x80000000u, (lbm_uint) array, ENC_SYM_ARRAY_TYPE(((0x30) << 4) | 0x00000000u));
1116
1117 *res = cell;
1118
1119 if (lbm_type_of(cell) == LBM_TYPE_SYMBOL0x00000000u) { // Out of heap memory
1120 lbm_memory_free((lbm_uint*)array->data);
1121 lbm_memory_free((lbm_uint*)array);
1122 return 0;
1123 }
1124
1125 lbm_heap_state.num_alloc_arrays ++;
1126
1127 return 1;
1128}
1129
1130// Convert a C array into an lbm_array.
1131// if the array is in LBM_MEMORY, the lifetime will be managed by the GC.
1132int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) {
1133
1134 lbm_array_header_t *array = NULL((void*)0);
1135 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_ARRAY_TYPE(((0x30) << 4) | 0x00000000u));
1136
1137 if (lbm_type_of(cell) == LBM_TYPE_SYMBOL0x00000000u) { // Out of heap memory
1138 *value = cell;
1139 return 0;
1140 }
1141
1142 array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t));
1143
1144 if (array == NULL((void*)0)) {
1145 *value = ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u);
1146 return 0;
1147 }
1148
1149 array->data = (lbm_uint*)data;
1150 array->size = num_elt;
1151
1152 lbm_set_car(cell, (lbm_uint)array);
1153
1154 cell = lbm_set_ptr_type(cell, LBM_TYPE_ARRAY0x80000000u);
1155 *value = cell;
1156 return 1;
1157}
1158
1159lbm_int lbm_heap_array_get_size(lbm_value arr) {
1160
1161 int r = -1;
1162 if (lbm_is_array_r(arr)) {
1163 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1164 if (header == NULL((void*)0)) {
1165 return r;
1166 }
1167 r = (lbm_int)header->size;
1168 }
1169 return r;
1170}
1171
1172const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) {
1173 uint8_t *r = NULL((void*)0);
1174 if (lbm_is_array_r(arr)) {
1175 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1176 if (header == NULL((void*)0)) {
1177 return r;
1178 }
1179 r = (uint8_t*)header->data;
1180 }
1181 return r;
1182}
1183
1184uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) {
1185 uint8_t *r = NULL((void*)0);
1186 if (lbm_is_array_rw(arr)) {
1187 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1188 if (header == NULL((void*)0)) {
1189 return r;
1190 }
1191 r = (uint8_t*)header->data;
1192 }
1193 return r;
1194}
1195
1196
1197/* Explicitly freeing an array.
1198
1199 This is a highly unsafe operation and can only be safely
1200 used if the heap cell that points to the array has not been made
1201 accessible to the program.
1202
1203 So This function can be used to free an array in case an array
1204 is being constructed and some error case appears while doing so
1205 If the array still have not become available it can safely be
1206 "explicitly" freed.
1207
1208 The problem is that if the "array" heap-cell is made available to
1209 the program, this cell can easily be duplicated and we would have
1210 to search the entire heap to find all cells pointing to the array
1211 memory in question and "null"-them out before freeing the memory
1212*/
1213
1214int lbm_heap_explicit_free_array(lbm_value arr) {
1215
1216 int r = 0;
1217 if (lbm_is_array_rw(arr)) {
1218
1219 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr);
1220 if (header == NULL((void*)0)) {
1221 return 0;
1222 }
1223 lbm_memory_free((lbm_uint*)header->data);
1224 lbm_memory_free((lbm_uint*)header);
1225
1226 arr = lbm_set_ptr_type(arr, LBM_TYPE_CONS0x10000000u);
1227 lbm_set_car(arr, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1228 lbm_set_cdr(arr, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1229 r = 1;
1230 }
1231
1232 return r;
1233}
1234
1235lbm_uint lbm_size_of(lbm_type t) {
1236 lbm_uint s = 0;
1237 switch(t) {
1238 case LBM_TYPE_BYTE0x00000004u:
1239 s = 1;
1240 break;
1241 case LBM_TYPE_I0x00000008u: /* fall through */
1242 case LBM_TYPE_U0x0000000Cu:
1243 case LBM_TYPE_SYMBOL0x00000000u:
1244 s = sizeof(lbm_uint);
1245 break;
1246 case LBM_TYPE_I320x28000000u: /* fall through */
1247 case LBM_TYPE_U320x38000000u:
1248 case LBM_TYPE_FLOAT0x68000000u:
1249 s = 4;
1250 break;
1251 case LBM_TYPE_I640x48000000u: /* fall through */
1252 case LBM_TYPE_U640x58000000u:
1253 case LBM_TYPE_DOUBLE0x78000000u:
1254 s = 8;
1255 break;
1256 }
1257 return s;
1258}
1259
1260static bool_Bool dummy_flash_write(lbm_uint ix, lbm_uint val) {
1261 (void)ix;
1262 (void)val;
1263 return false0;
1264}
1265
1266static const_heap_write_fun const_heap_write = dummy_flash_write;
1267
1268int lbm_const_heap_init(const_heap_write_fun w_fun,
1269 lbm_const_heap_t *heap,
1270 lbm_uint *addr,
1271 lbm_uint num_words) {
1272 if (((uintptr_t)addr % 4) != 0) return 0;
1273 if ((num_words % 2) != 0) return 0;
1274
1275 if (!lbm_const_heap_mutex_initialized) {
1276 mutex_init(&lbm_const_heap_mutex);
1277 lbm_const_heap_mutex_initialized = true1;
1278 }
1279
1280 if (!lbm_mark_mutex_initialized) {
1281 mutex_init(&lbm_mark_mutex);
1282 lbm_mark_mutex_initialized = true1;
1283 }
1284
1285 const_heap_write = w_fun;
1286
1287 heap->heap = addr;
1288 heap->size = num_words;
1289 heap->next = 0;
1290
1291 lbm_const_heap_state = heap;
1292 // ref_cell views the lbm_uint array as an lbm_cons_t array
1293 lbm_heaps[1] = (lbm_cons_t*)addr;
1294 return 1;
1295}
1296
1297lbm_flash_status lbm_allocate_const_cell(lbm_value *res) {
1298 lbm_flash_status r = LBM_FLASH_FULL;
1299
1300 mutex_lock(&lbm_const_heap_mutex);
1301 // waste a cell if we have ended up unaligned after writing an array to flash.
1302 if (lbm_const_heap_state->next % 2 == 1) {
1303 lbm_const_heap_state->next++;
1304 }
1305
1306 if (lbm_const_heap_state &&
1307 (lbm_const_heap_state->next+1) < lbm_const_heap_state->size) {
1308 // A cons cell uses two words.
1309 lbm_value cell = lbm_const_heap_state->next;
1310 lbm_const_heap_state->next += 2;
1311 *res = (cell << LBM_ADDRESS_SHIFT2) | LBM_PTR_BIT0x00000001u | LBM_TYPE_CONS0x10000000u | LBM_PTR_TO_CONSTANT_BIT0x04000000u;
1312 r = LBM_FLASH_WRITE_OK;
1313 }
1314 mutex_unlock(&lbm_const_heap_mutex);
1315 return r;
1316}
1317
1318lbm_flash_status lbm_write_const_raw(lbm_uint *data, lbm_uint n, lbm_uint *res) {
1319
1320 lbm_flash_status r = LBM_FLASH_FULL;
1321
1322 if (lbm_const_heap_state &&
1323 (lbm_const_heap_state->next + n) < lbm_const_heap_state->size) {
1324 lbm_uint ix = lbm_const_heap_state->next;
1325
1326 for (unsigned int i = 0; i < n; i ++) {
1327 if (!const_heap_write(ix + i, ((lbm_uint*)data)[i]))
1328 return LBM_FLASH_WRITE_ERROR;
1329 }
1330 lbm_const_heap_state->next += n;
1331 *res = (lbm_uint)&lbm_const_heap_state->heap[ix];
1332 r = LBM_FLASH_WRITE_OK;
1333 }
1334 return r;
1335}
1336
1337lbm_flash_status write_const_cdr(lbm_value cell, lbm_value val) {
1338 lbm_uint addr = lbm_dec_ptr(cell);
1339 if (const_heap_write(addr+1, val))
1340 return LBM_FLASH_WRITE_OK;
1341 return LBM_FLASH_WRITE_ERROR;
1342}
1343
1344lbm_flash_status write_const_car(lbm_value cell, lbm_value val) {
1345 lbm_uint addr = lbm_dec_ptr(cell);
1346 if (const_heap_write(addr, val))
1347 return LBM_FLASH_WRITE_OK;
1348 return LBM_FLASH_WRITE_ERROR;
1349}
1350
1351lbm_uint lbm_flash_memory_usage(void) {
1352 return lbm_const_heap_state->next;
1353}

./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