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
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
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 | |
38 | static inline lbm_value lbm_set_gc_mark(lbm_value x) { |
39 | return x | LBM_GC_MARKED; |
40 | } |
41 | |
42 | static inline lbm_value lbm_clr_gc_mark(lbm_value x) { |
43 | return x & ~LBM_GC_MASK; |
44 | } |
45 | |
46 | static inline bool lbm_get_gc_mark(lbm_value x) { |
47 | return x & LBM_GC_MASK; |
48 | } |
49 | |
50 | |
51 | static inline bool lbm_get_gc_flag(lbm_value x) { |
52 | return x & LBM_GC_MARKED; |
53 | } |
54 | |
55 | static inline lbm_value lbm_set_gc_flag(lbm_value x) { |
56 | return x | LBM_GC_MARKED; |
57 | } |
58 | |
59 | static inline lbm_value lbm_clr_gc_flag(lbm_value x) { |
60 | return x & ~LBM_GC_MASK; |
61 | } |
62 | |
63 | |
64 | lbm_heap_state_t lbm_heap_state; |
65 | |
66 | lbm_const_heap_t *lbm_const_heap_state; |
67 | |
68 | lbm_cons_t *lbm_heaps[2] = {NULL, NULL}; |
69 | |
70 | static mutex_t lbm_const_heap_mutex; |
71 | static bool lbm_const_heap_mutex_initialized = false; |
72 | |
73 | static mutex_t lbm_mark_mutex; |
74 | static bool lbm_mark_mutex_initialized = false; |
75 | |
76 | #ifdef USE_GC_PTR_REV |
77 | void lbm_gc_lock(void) { |
78 | mutex_lock(&lbm_mark_mutex); |
79 | } |
80 | void lbm_gc_unlock(void) { |
81 | mutex_unlock(&lbm_mark_mutex); |
82 | } |
83 | #else |
84 | void lbm_gc_lock(void) { |
85 | } |
86 | void lbm_gc_unlock(void) { |
87 | } |
88 | #endif |
89 | |
90 | |
91 | |
92 | |
93 | lbm_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_TYPE)); |
96 | if (lbm_type_of(i) == LBM_TYPE_SYMBOL) return i; |
97 | return lbm_set_ptr_type(i, LBM_TYPE_I32); |
98 | #else |
99 | return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_I32; |
100 | #endif |
101 | } |
102 | |
103 | lbm_value lbm_enc_u32(uint32_t x) { |
104 | #ifndef LBM64 |
105 | lbm_value u = lbm_cons(x, lbm_enc_sym(SYM_RAW_U_TYPE)); |
106 | if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
107 | return lbm_set_ptr_type(u, LBM_TYPE_U32); |
108 | #else |
109 | return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_U32; |
110 | #endif |
111 | } |
112 | |
113 | lbm_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_TYPE)); |
118 | if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f; |
119 | return lbm_set_ptr_type(f, LBM_TYPE_FLOAT); |
120 | #else |
121 | lbm_uint t = 0; |
122 | memcpy(&t, &x, sizeof(float)); |
123 | return (((lbm_uint)t) << LBM_VAL_SHIFT) | LBM_TYPE_FLOAT; |
124 | #endif |
125 | } |
126 | |
127 | lbm_value lbm_enc_i64(int64_t x) { |
128 | #ifndef LBM64 |
129 | lbm_value res = lbm_enc_sym(SYM_MERROR); |
130 | lbm_uint* storage = lbm_memory_allocate(2); |
131 | if (storage) { |
132 | res = lbm_cons((lbm_uint)storage, lbm_enc_sym(SYM_IND_I_TYPE)); |
133 | if (lbm_type_of(res) != LBM_TYPE_SYMBOL) { |
134 | memcpy(storage,&x, 8); |
135 | res = lbm_set_ptr_type(res, LBM_TYPE_I64); |
136 | } |
137 | } |
138 | return res; |
139 | #else |
140 | lbm_value u = lbm_cons((uint64_t)x, lbm_enc_sym(SYM_RAW_I_TYPE)); |
141 | if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
142 | return lbm_set_ptr_type(u, LBM_TYPE_I64); |
143 | #endif |
144 | } |
145 | |
146 | lbm_value lbm_enc_u64(uint64_t x) { |
147 | #ifndef LBM64 |
148 | lbm_value res = lbm_enc_sym(SYM_MERROR); |
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_TYPE)); |
152 | if (lbm_type_of(res) != LBM_TYPE_SYMBOL) { |
153 | memcpy(storage,&x, sizeof(uint64_t)); |
154 | res = lbm_set_ptr_type(res, LBM_TYPE_U64); |
155 | } |
156 | } |
157 | return res; |
158 | #else |
159 | lbm_value u = lbm_cons(x, lbm_enc_sym(SYM_RAW_U_TYPE)); |
160 | if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
161 | return lbm_set_ptr_type(u, LBM_TYPE_U64); |
162 | #endif |
163 | } |
164 | |
165 | lbm_value lbm_enc_double(double x) { |
166 | #ifndef LBM64 |
167 | lbm_value res = lbm_enc_sym(SYM_MERROR); |
168 | lbm_uint* storage = lbm_memory_allocate(2); |
169 | if (storage) { |
170 | res = lbm_cons((lbm_uint)storage, lbm_enc_sym(SYM_IND_F_TYPE)); |
171 | if (lbm_type_of(res) != LBM_TYPE_SYMBOL) { |
172 | memcpy(storage,&x, 8); |
173 | res = lbm_set_ptr_type(res, LBM_TYPE_DOUBLE); |
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_TYPE)); |
181 | if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f; |
182 | return lbm_set_ptr_type(f, LBM_TYPE_DOUBLE); |
183 | #endif |
184 | } |
185 | |
186 | float 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_SHIFT); |
194 | float f_tmp; |
195 | memcpy(&f_tmp, &tmp, sizeof(float)); |
196 | return f_tmp; |
197 | #endif |
198 | } |
199 | |
200 | double 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) return 0; |
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 | |
215 | uint64_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) return 0; |
220 | memcpy(&u, data, 8); |
221 | return u; |
222 | #else |
223 | return (uint64_t)lbm_car(x); |
224 | #endif |
225 | } |
226 | |
227 | int64_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) return 0; |
232 | memcpy(&i, data, 8); |
233 | return i; |
234 | #else |
235 | return (int64_t)lbm_car(x); |
236 | #endif |
237 | } |
238 | |
239 | char *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 | |
250 | lbm_char_channel_t *lbm_dec_channel(lbm_value val) { |
251 | lbm_char_channel_t *res = NULL; |
252 | |
253 | if (lbm_type_of(val) == LBM_TYPE_CHANNEL) { |
254 | res = (lbm_char_channel_t *)lbm_car(val); |
255 | } |
256 | return res; |
257 | } |
258 | |
259 | lbm_uint lbm_dec_custom(lbm_value val) { |
260 | lbm_uint res = 0; |
261 | if (lbm_type_of(val) == LBM_TYPE_CUSTOM) { |
262 | res = (lbm_uint)lbm_car(val); |
263 | } |
264 | return res; |
265 | } |
266 | |
267 | uint8_t lbm_dec_as_char(lbm_value a) { |
268 | switch (lbm_type_of_functional(a)) { |
269 | case LBM_TYPE_CHAR: |
270 | return (uint8_t) lbm_dec_char(a); |
271 | case LBM_TYPE_I: |
272 | return (uint8_t) lbm_dec_i(a); |
273 | case LBM_TYPE_U: |
274 | return (uint8_t) lbm_dec_u(a); |
275 | case LBM_TYPE_I32: |
276 | return (uint8_t) lbm_dec_i32(a); |
277 | case LBM_TYPE_U32: |
278 | return (uint8_t) lbm_dec_u32(a); |
279 | case LBM_TYPE_FLOAT: |
280 | return (uint8_t)lbm_dec_float(a); |
281 | case LBM_TYPE_I64: |
282 | return (uint8_t) lbm_dec_i64(a); |
283 | case LBM_TYPE_U64: |
284 | return (uint8_t) lbm_dec_u64(a); |
285 | case LBM_TYPE_DOUBLE: |
286 | return (uint8_t) lbm_dec_double(a); |
287 | } |
288 | return 0; |
289 | } |
290 | |
291 | uint32_t lbm_dec_as_u32(lbm_value a) { |
292 | switch (lbm_type_of_functional(a)) { |
293 | case LBM_TYPE_CHAR: |
294 | return (uint32_t) lbm_dec_char(a); |
295 | case LBM_TYPE_I: |
296 | return (uint32_t) lbm_dec_i(a); |
297 | case LBM_TYPE_U: |
298 | return (uint32_t) lbm_dec_u(a); |
299 | case LBM_TYPE_I32: |
300 | case LBM_TYPE_U32: |
301 | return (uint32_t) lbm_dec_u32(a); |
302 | case LBM_TYPE_FLOAT: |
303 | return (uint32_t)lbm_dec_float(a); |
304 | case LBM_TYPE_I64: |
305 | return (uint32_t) lbm_dec_i64(a); |
306 | case LBM_TYPE_U64: |
307 | return (uint32_t) lbm_dec_u64(a); |
308 | case LBM_TYPE_DOUBLE: |
309 | return (uint32_t) lbm_dec_double(a); |
310 | } |
311 | return 0; |
312 | } |
313 | |
314 | int32_t lbm_dec_as_i32(lbm_value a) { |
315 | switch (lbm_type_of_functional(a)) { |
316 | case LBM_TYPE_CHAR: |
317 | return (int32_t) lbm_dec_char(a); |
318 | case LBM_TYPE_I: |
319 | return (int32_t) lbm_dec_i(a); |
320 | case LBM_TYPE_U: |
321 | return (int32_t) lbm_dec_u(a); |
322 | case LBM_TYPE_I32: |
323 | return (int32_t) lbm_dec_i32(a); |
324 | case LBM_TYPE_U32: |
325 | return (int32_t) lbm_dec_u32(a); |
326 | case LBM_TYPE_FLOAT: |
327 | return (int32_t) lbm_dec_float(a); |
328 | case LBM_TYPE_I64: |
329 | return (int32_t) lbm_dec_i64(a); |
330 | case LBM_TYPE_U64: |
331 | return (int32_t) lbm_dec_u64(a); |
332 | case LBM_TYPE_DOUBLE: |
333 | return (int32_t) lbm_dec_double(a); |
334 | |
335 | } |
336 | return 0; |
337 | } |
338 | |
339 | int64_t lbm_dec_as_i64(lbm_value a) { |
340 | switch (lbm_type_of_functional(a)) { |
341 | case LBM_TYPE_CHAR: |
342 | return (int64_t) lbm_dec_char(a); |
343 | case LBM_TYPE_I: |
344 | return lbm_dec_i(a); |
345 | case LBM_TYPE_U: |
346 | return (int64_t) lbm_dec_u(a); |
347 | case LBM_TYPE_I32: |
348 | return (int64_t) lbm_dec_i32(a); |
349 | case LBM_TYPE_U32: |
350 | return (int64_t) lbm_dec_u32(a); |
351 | case LBM_TYPE_FLOAT: |
352 | return (int64_t) lbm_dec_float(a); |
353 | case LBM_TYPE_I64: |
354 | return (int64_t) lbm_dec_i64(a); |
355 | case LBM_TYPE_U64: |
356 | return (int64_t) lbm_dec_u64(a); |
357 | case LBM_TYPE_DOUBLE: |
358 | return (int64_t) lbm_dec_double(a); |
359 | } |
360 | return 0; |
361 | } |
362 | |
363 | uint64_t lbm_dec_as_u64(lbm_value a) { |
364 | switch (lbm_type_of_functional(a)) { |
365 | case LBM_TYPE_CHAR: |
366 | return (uint64_t) lbm_dec_char(a); |
367 | case LBM_TYPE_I: |
368 | return (uint64_t) lbm_dec_i(a); |
369 | case LBM_TYPE_U: |
370 | return lbm_dec_u(a); |
371 | case LBM_TYPE_I32: |
372 | return (uint64_t) lbm_dec_i32(a); |
373 | case LBM_TYPE_U32: |
374 | return (uint64_t) lbm_dec_u32(a); |
375 | case LBM_TYPE_FLOAT: |
376 | return (uint64_t)lbm_dec_float(a); |
377 | case LBM_TYPE_I64: |
378 | return (uint64_t) lbm_dec_i64(a); |
379 | case LBM_TYPE_U64: |
380 | return (uint64_t) lbm_dec_u64(a); |
381 | case LBM_TYPE_DOUBLE: |
382 | return (uint64_t) lbm_dec_double(a); |
383 | } |
384 | return 0; |
385 | } |
386 | |
387 | float lbm_dec_as_float(lbm_value a) { |
388 | |
389 | switch (lbm_type_of_functional(a)) { |
390 | case LBM_TYPE_CHAR: |
391 | return (float) lbm_dec_char(a); |
392 | case LBM_TYPE_I: |
393 | return (float) lbm_dec_i(a); |
394 | case LBM_TYPE_U: |
395 | return (float) lbm_dec_u(a); |
396 | case LBM_TYPE_I32: |
397 | return (float) lbm_dec_i32(a); |
398 | case LBM_TYPE_U32: |
399 | return (float) lbm_dec_u32(a); |
400 | case LBM_TYPE_FLOAT: |
401 | return (float) lbm_dec_float(a); |
402 | case LBM_TYPE_I64: |
403 | return (float) lbm_dec_i64(a); |
404 | case LBM_TYPE_U64: |
405 | return (float) lbm_dec_u64(a); |
406 | case LBM_TYPE_DOUBLE: |
407 | return (float) lbm_dec_double(a); |
408 | } |
409 | return 0; |
410 | } |
411 | |
412 | double lbm_dec_as_double(lbm_value a) { |
413 | |
414 | switch (lbm_type_of_functional(a)) { |
415 | case LBM_TYPE_CHAR: |
416 | return (double) lbm_dec_char(a); |
417 | case LBM_TYPE_I: |
418 | return (double) lbm_dec_i(a); |
419 | case LBM_TYPE_U: |
420 | return (double) lbm_dec_u(a); |
421 | case LBM_TYPE_I32: |
422 | return (double) lbm_dec_i32(a); |
423 | case LBM_TYPE_U32: |
424 | return (double) lbm_dec_u32(a); |
425 | case LBM_TYPE_FLOAT: |
426 | return (double) lbm_dec_float(a); |
427 | case LBM_TYPE_I64: |
428 | return (double) lbm_dec_i64(a); |
429 | case LBM_TYPE_U64: |
430 | return (double) lbm_dec_u64(a); |
431 | case LBM_TYPE_DOUBLE: |
432 | return (double) lbm_dec_double(a); |
433 | } |
434 | return 0; |
435 | } |
436 | |
437 | |
438 | |
439 | |
440 | static 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 | |
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; |
453 | t->cdr = lbm_enc_cons_ptr(i); |
454 | } |
455 | |
456 | |
457 | t = lbm_ref_cell(lbm_enc_cons_ptr(num_cells-1)); |
458 | t->cdr = ENC_SYM_NIL; |
459 | |
460 | return 1; |
461 | } |
462 | |
463 | void lbm_nil_freelist(void) { |
464 | lbm_heap_state.freelist = ENC_SYM_NIL; |
465 | lbm_heap_state.num_alloc = lbm_heap_state.heap_size; |
466 | } |
467 | |
468 | static 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 | |
486 | void 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 | |
493 | int 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) 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 | |
511 | lbm_uint lbm_heap_num_free(void) { |
512 | return lbm_heap_state.heap_size - lbm_heap_state.num_alloc; |
513 | } |
514 | |
515 | lbm_value lbm_heap_allocate_cell(lbm_type ptr_type, lbm_value car, lbm_value cdr) { |
516 | lbm_value res; |
517 | |
518 | res = lbm_heap_state.freelist; |
519 | if (lbm_type_of(res) == LBM_TYPE_CONS) { |
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; |
529 | } |
530 | |
531 | lbm_value lbm_heap_allocate_list(lbm_uint n) { |
532 | if (n == 0) return ENC_SYM_NIL; |
533 | if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
534 | |
535 | lbm_value curr = lbm_heap_state.freelist; |
536 | lbm_value res = curr; |
537 | if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
538 | |
539 | lbm_cons_t *c_cell = NULL; |
540 | lbm_uint count = 0; |
541 | do { |
542 | c_cell = lbm_ref_cell(curr); |
543 | c_cell->car = ENC_SYM_NIL; |
544 | curr = c_cell->cdr; |
545 | count ++; |
546 | } while (count < n); |
547 | lbm_heap_state.freelist = curr; |
548 | c_cell->cdr = ENC_SYM_NIL; |
549 | lbm_heap_state.num_alloc+=count; |
550 | return res; |
551 | } |
552 | return ENC_SYM_FATAL_ERROR; |
553 | } |
554 | |
555 | lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) { |
556 | if (n == 0) return ENC_SYM_NIL; |
557 | if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
558 | |
559 | lbm_value curr = lbm_heap_state.freelist; |
560 | lbm_value res = curr; |
561 | if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
562 | |
563 | lbm_cons_t *c_cell = NULL; |
564 | unsigned int count = 0; |
565 | do { |
566 | c_cell = lbm_ref_cell(curr); |
567 | c_cell->car = 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; |
573 | lbm_heap_state.num_alloc+=count; |
574 | return res; |
575 | } |
576 | return ENC_SYM_FATAL_ERROR; |
577 | } |
578 | |
579 | lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) { |
580 | va_list valist; |
581 | va_start(valist, n); |
582 | lbm_value r = lbm_heap_allocate_list_init_va(n, valist); |
583 | va_end(valist); |
584 | return r; |
585 | } |
586 | |
587 | lbm_uint lbm_heap_num_allocated(void) { |
588 | return lbm_heap_state.num_alloc; |
589 | } |
590 | lbm_uint lbm_heap_size(void) { |
591 | return lbm_heap_state.heap_size; |
592 | } |
593 | |
594 | lbm_uint lbm_heap_size_bytes(void) { |
595 | return lbm_heap_state.heap_bytes; |
596 | } |
597 | |
598 | void lbm_get_heap_state(lbm_heap_state_t *res) { |
599 | *res = lbm_heap_state; |
600 | } |
601 | |
602 | lbm_uint lbm_get_gc_stack_max(void) { |
603 | return lbm_heap_state.gc_stack.max_sp; |
604 | } |
605 | |
606 | lbm_uint lbm_get_gc_stack_size(void) { |
607 | return lbm_heap_state.gc_stack.size; |
608 | } |
609 | |
610 | #ifdef USE_GC_PTR_REV |
611 | static inline void value_assign(lbm_value *a, lbm_value b) { |
612 | lbm_value a_old = *a & LBM_GC_MASK; |
613 | *a = a_old | (b & ~LBM_GC_MASK); |
614 | } |
615 | |
616 | void lbm_gc_mark_phase(lbm_value root) { |
617 | bool work_to_do = true; |
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); |
624 | |
625 | while (work_to_do) { |
626 | |
627 | while (lbm_is_ptr(curr) && |
628 | (lbm_dec_ptr(curr) != LBM_PTR_NULL) && |
629 | ((curr & LBM_PTR_TO_CONSTANT_BIT) == 0) && |
630 | !lbm_get_gc_mark(lbm_cdr(curr))) { |
631 | |
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 | |
642 | } |
643 | while (lbm_is_ptr(prev) && |
644 | (lbm_dec_ptr(prev) != LBM_PTR_NULL) && |
645 | lbm_get_gc_flag(lbm_car(prev)) ) { |
646 | |
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) { |
657 | work_to_do = false; |
658 | } else if (lbm_is_ptr(prev)) { |
659 | |
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 |
673 | extern eval_context_t *ctx_running; |
674 | void 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_BIT)) { |
| 10 | | Assuming the condition is false | |
|
| 11 | | Assuming the condition is false | |
|
| |
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 | |
|
| |
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_FIRST && |
| 15 | | Assuming 't_ptr' is < LBM_NON_CONS_POINTER_TYPE_FIRST | |
|
697 | t_ptr <= LBM_NON_CONS_POINTER_TYPE_LAST) continue; |
698 | |
699 | if (cell->car == ENC_SYM_CONT) { |
| 16 | | Assuming the condition is true | |
|
| |
700 | lbm_array_header_t *arr = (lbm_array_header_t*)lbm_car(cell->cdr); |
| |
| 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_INTERNAL) == LBM_CONTINUATION_INTERNAL)) { |
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; |
719 | } |
720 | } |
721 | #endif |
722 | |
723 | |
724 | void 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); |
731 | lbm_cons_t *b = lbm_ref_cell(c->car); |
732 | b->cdr = lbm_set_gc_mark(b->cdr); |
733 | lbm_gc_mark_phase(b->cdr); |
734 | lbm_heap_state.gc_marked +=2; |
735 | curr = c->cdr; |
736 | } |
737 | } |
738 | |
739 | |
740 | void 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_FIRST && |
746 | pt_t <= LBM_POINTER_TYPE_LAST && |
747 | pt_v < lbm_heap_state.heap_size) { |
748 | lbm_gc_mark_phase(aux_data[i]); |
749 | } |
750 | } |
751 | } |
752 | } |
753 | |
754 | void 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 | |
761 | int 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 | |
770 | |
771 | if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL) { |
772 | switch(lbm_dec_sym(heap[i].cdr)) { |
773 | |
774 | case SYM_IND_I_TYPE: |
775 | case SYM_IND_U_TYPE: |
776 | case SYM_IND_F_TYPE: |
777 | lbm_memory_free((lbm_uint*)heap[i].car); |
778 | break; |
779 | case SYM_ARRAY_TYPE:{ |
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_TYPE:{ |
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_TYPE: { |
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 | |
804 | lbm_uint addr = lbm_enc_cons_ptr(i); |
805 | |
806 | |
807 | heap[i].car = ENC_SYM_RECOVERED; |
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 | |
817 | void 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 | |
824 | lbm_value lbm_cons(lbm_value car, lbm_value cdr) { |
825 | return lbm_heap_allocate_cell(LBM_TYPE_CONS, car, cdr); |
826 | } |
827 | |
828 | lbm_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_SYMBOL && |
| 20 | | Assuming the condition is true | |
|
| |
836 | lbm_dec_sym(c) == SYM_NIL) { |
| 21 | | Assuming the condition is true | |
|
837 | return ENC_SYM_NIL; |
| |
838 | } |
839 | |
840 | return ENC_SYM_TERROR; |
841 | } |
842 | |
843 | lbm_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_NIL) { |
853 | return tmp; |
854 | } |
855 | } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL) { |
856 | return c; |
857 | } |
858 | return ENC_SYM_TERROR; |
859 | } |
860 | |
861 | |
862 | lbm_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_NIL) { |
872 | return tmp; |
873 | } |
874 | } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL) { |
875 | return c; |
876 | } |
877 | return ENC_SYM_TERROR; |
878 | } |
879 | |
880 | lbm_value lbm_cdr(lbm_value c){ |
881 | |
882 | if (lbm_type_of(c) == LBM_TYPE_SYMBOL && |
883 | lbm_dec_sym(c) == SYM_NIL) { |
884 | return ENC_SYM_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; |
892 | } |
893 | |
894 | lbm_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_NIL) { |
903 | return ENC_SYM_NIL; |
904 | } |
905 | return ENC_SYM_TERROR; |
906 | } |
907 | |
908 | int lbm_set_car(lbm_value c, lbm_value v) { |
909 | int r = 0; |
910 | |
911 | if (lbm_type_of(c) == LBM_TYPE_CONS) { |
912 | lbm_cons_t *cell = lbm_ref_cell(c); |
913 | cell->car = v; |
914 | r = 1; |
915 | } |
916 | return r; |
917 | } |
918 | |
919 | int 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 | |
929 | int 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 | |
941 | lbm_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 | |
952 | |
953 | unsigned int lbm_list_length_pred(lbm_value c, bool *pres, bool (*pred)(lbm_value)) { |
954 | bool res = true; |
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 | |
967 | lbm_value lbm_list_reverse(lbm_value list) { |
968 | if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
969 | return list; |
970 | } |
971 | |
972 | lbm_value curr = list; |
973 | |
974 | lbm_value new_list = ENC_SYM_NIL; |
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_SYMBOL) { |
979 | return ENC_SYM_MERROR; |
980 | } |
981 | curr = lbm_cdr(curr); |
982 | } |
983 | return new_list; |
984 | } |
985 | |
986 | lbm_value lbm_list_destructive_reverse(lbm_value list) { |
987 | if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
988 | return list; |
989 | } |
990 | lbm_value curr = list; |
991 | lbm_value last_cell = ENC_SYM_NIL; |
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 | |
1003 | lbm_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; |
1011 | } |
1012 | if (copy_n == 0) return ENC_SYM_NIL; |
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 | |
1029 | |
1030 | lbm_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_CONS) { |
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; |
1044 | } |
1045 | |
1046 | lbm_value lbm_list_drop(unsigned int n, lbm_value ls) { |
1047 | lbm_value curr = ls; |
1048 | while (lbm_type_of_functional(curr) == LBM_TYPE_CONS && |
1049 | n > 0) { |
1050 | curr = lbm_cdr(curr); |
1051 | n --; |
1052 | } |
1053 | return curr; |
1054 | } |
1055 | |
1056 | lbm_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; |
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; |
1074 | } |
1075 | } |
1076 | |
1077 | |
1078 | |
1079 | |
1080 | |
1081 | |
1082 | int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){ |
1083 | |
1084 | lbm_array_header_t *array = NULL; |
1085 | |
1086 | array = (lbm_array_header_t*)lbm_memory_allocate(sizeof(lbm_array_header_t) / sizeof(lbm_uint)); |
1087 | |
1088 | if (array == NULL) { |
1089 | *res = ENC_SYM_MERROR; |
1090 | return 0; |
1091 | } |
1092 | |
1093 | array->data = (lbm_uint*)lbm_malloc(size); |
1094 | |
1095 | if (array->data == NULL) { |
1096 | lbm_memory_free((lbm_uint*)array); |
1097 | *res = ENC_SYM_MERROR; |
1098 | return 0; |
1099 | } |
1100 | memset(array->data, 0, size); |
1101 | array->size = size; |
1102 | |
1103 | |
1104 | lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_ARRAY, (lbm_uint) array, ENC_SYM_ARRAY_TYPE); |
1105 | |
1106 | *res = cell; |
1107 | |
1108 | if (lbm_type_of(cell) == LBM_TYPE_SYMBOL) { |
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 | |
1120 | |
1121 | int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) { |
1122 | |
1123 | lbm_array_header_t *array = NULL; |
1124 | lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE); |
1125 | |
1126 | if (lbm_type_of(cell) == LBM_TYPE_SYMBOL) { |
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) { |
1134 | *value = ENC_SYM_MERROR; |
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_ARRAY); |
1144 | *value = cell; |
1145 | return 1; |
1146 | } |
1147 | |
1148 | lbm_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) { |
1154 | return r; |
1155 | } |
1156 | r = (lbm_int)header->size; |
1157 | } |
1158 | return r; |
1159 | } |
1160 | |
1161 | const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) { |
1162 | uint8_t *r = NULL; |
1163 | if (lbm_is_array_r(arr)) { |
1164 | lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr); |
1165 | if (header == NULL) { |
1166 | return r; |
1167 | } |
1168 | r = (uint8_t*)header->data; |
1169 | } |
1170 | return r; |
1171 | } |
1172 | |
1173 | uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) { |
1174 | uint8_t *r = NULL; |
1175 | if (lbm_is_array_rw(arr)) { |
1176 | lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr); |
1177 | if (header == NULL) { |
1178 | return r; |
1179 | } |
1180 | r = (uint8_t*)header->data; |
1181 | } |
1182 | return r; |
1183 | } |
1184 | |
1185 | |
1186 | |
1187 | |
1188 | |
1189 | |
1190 | |
1191 | |
1192 | |
1193 | |
1194 | |
1195 | |
1196 | |
1197 | |
1198 | |
1199 | |
1200 | |
1201 | |
1202 | |
1203 | int 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) { |
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_CONS); |
1216 | lbm_set_car(arr, ENC_SYM_NIL); |
1217 | lbm_set_cdr(arr, ENC_SYM_NIL); |
1218 | r = 1; |
1219 | } |
1220 | |
1221 | return r; |
1222 | } |
1223 | |
1224 | lbm_uint lbm_size_of(lbm_type t) { |
1225 | lbm_uint s = 0; |
1226 | switch(t) { |
1227 | case LBM_TYPE_BYTE: |
1228 | s = 1; |
1229 | break; |
1230 | case LBM_TYPE_I: |
1231 | case LBM_TYPE_U: |
1232 | case LBM_TYPE_SYMBOL: |
1233 | s = sizeof(lbm_uint); |
1234 | break; |
1235 | case LBM_TYPE_I32: |
1236 | case LBM_TYPE_U32: |
1237 | case LBM_TYPE_FLOAT: |
1238 | s = 4; |
1239 | break; |
1240 | case LBM_TYPE_I64: |
1241 | case LBM_TYPE_U64: |
1242 | case LBM_TYPE_DOUBLE: |
1243 | s = 8; |
1244 | break; |
1245 | } |
1246 | return s; |
1247 | } |
1248 | |
1249 | static bool dummy_flash_write(lbm_uint ix, lbm_uint val) { |
1250 | (void)ix; |
1251 | (void)val; |
1252 | return false; |
1253 | } |
1254 | |
1255 | static const_heap_write_fun const_heap_write = dummy_flash_write; |
1256 | |
1257 | int 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 = true; |
1267 | } |
1268 | |
1269 | if (!lbm_mark_mutex_initialized) { |
1270 | mutex_init(&lbm_mark_mutex); |
1271 | lbm_mark_mutex_initialized = true; |
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 | |
1282 | lbm_heaps[1] = (lbm_cons_t*)addr; |
1283 | return 1; |
1284 | } |
1285 | |
1286 | lbm_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 | |
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 | |
1298 | lbm_value cell = lbm_const_heap_state->next; |
1299 | lbm_const_heap_state->next += 2; |
1300 | *res = (cell << LBM_ADDRESS_SHIFT) | LBM_PTR_BIT | LBM_TYPE_CONS | LBM_PTR_TO_CONSTANT_BIT; |
1301 | r = LBM_FLASH_WRITE_OK; |
1302 | } |
1303 | mutex_unlock(&lbm_const_heap_mutex); |
1304 | return r; |
1305 | } |
1306 | |
1307 | lbm_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 | |
1326 | lbm_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 | |
1333 | lbm_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 | |
1340 | lbm_uint lbm_flash_memory_usage(void) { |
1341 | return lbm_const_heap_state->next; |
1342 | } |