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
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 | |
517 | lbm_value res; |
518 | |
519 | |
520 | res = lbm_heap_state.freelist; |
521 | |
522 | if (lbm_type_of(res) == LBM_TYPE_CONS) { |
523 | lbm_uint heap_ix = lbm_dec_ptr(res); |
524 | |
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_SYMBOL) && |
535 | (lbm_dec_sym(res) == SYM_NIL)) { |
536 | |
537 | return ENC_SYM_MERROR; |
538 | } |
539 | |
540 | return ENC_SYM_FATAL_ERROR; |
541 | } |
542 | |
543 | lbm_value lbm_heap_allocate_list(lbm_uint n) { |
544 | if (n == 0) return ENC_SYM_NIL; |
545 | if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
546 | |
547 | lbm_value curr = lbm_heap_state.freelist; |
548 | lbm_value res = curr; |
549 | if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
550 | |
551 | lbm_cons_t *c_cell = NULL; |
552 | lbm_uint count = 0; |
553 | do { |
554 | c_cell = lbm_ref_cell(curr); |
555 | c_cell->car = ENC_SYM_NIL; |
556 | curr = c_cell->cdr; |
557 | count ++; |
558 | } while (count < n); |
559 | lbm_heap_state.freelist = curr; |
560 | c_cell->cdr = ENC_SYM_NIL; |
561 | lbm_heap_state.num_alloc+=count; |
562 | return res; |
563 | } |
564 | return ENC_SYM_FATAL_ERROR; |
565 | } |
566 | |
567 | lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) { |
568 | if (n == 0) return ENC_SYM_NIL; |
569 | if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
570 | |
571 | lbm_value curr = lbm_heap_state.freelist; |
572 | lbm_value res = curr; |
573 | if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
574 | |
575 | lbm_cons_t *c_cell = NULL; |
576 | unsigned int count = 0; |
577 | do { |
578 | c_cell = lbm_ref_cell(curr); |
579 | c_cell->car = 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; |
585 | lbm_heap_state.num_alloc+=count; |
586 | return res; |
587 | } |
588 | return ENC_SYM_FATAL_ERROR; |
589 | } |
590 | |
591 | lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) { |
592 | va_list valist; |
593 | va_start(valist, n); |
594 | lbm_value r = lbm_heap_allocate_list_init_va(n, valist); |
595 | va_end(valist); |
596 | return r; |
597 | } |
598 | |
599 | lbm_uint lbm_heap_num_allocated(void) { |
600 | return lbm_heap_state.num_alloc; |
601 | } |
602 | lbm_uint lbm_heap_size(void) { |
603 | return lbm_heap_state.heap_size; |
604 | } |
605 | |
606 | lbm_uint lbm_heap_size_bytes(void) { |
607 | return lbm_heap_state.heap_bytes; |
608 | } |
609 | |
610 | void lbm_get_heap_state(lbm_heap_state_t *res) { |
611 | *res = lbm_heap_state; |
612 | } |
613 | |
614 | lbm_uint lbm_get_gc_stack_max(void) { |
615 | return lbm_heap_state.gc_stack.max_sp; |
616 | } |
617 | |
618 | lbm_uint lbm_get_gc_stack_size(void) { |
619 | return lbm_heap_state.gc_stack.size; |
620 | } |
621 | |
622 | #ifdef USE_GC_PTR_REV |
623 | static inline void value_assign(lbm_value *a, lbm_value b) { |
624 | lbm_value a_old = *a & LBM_GC_MASK; |
625 | *a = a_old | (b & ~LBM_GC_MASK); |
626 | } |
627 | |
628 | void lbm_gc_mark_phase(lbm_value root) { |
629 | bool work_to_do = true; |
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); |
636 | |
637 | while (work_to_do) { |
638 | |
639 | while (lbm_is_ptr(curr) && |
640 | (lbm_dec_ptr(curr) != LBM_PTR_NULL) && |
641 | ((curr & LBM_PTR_TO_CONSTANT_BIT) == 0) && |
642 | !lbm_get_gc_mark(lbm_cdr(curr))) { |
643 | |
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 | |
654 | } |
655 | while (lbm_is_ptr(prev) && |
656 | (lbm_dec_ptr(prev) != LBM_PTR_NULL) && |
657 | lbm_get_gc_flag(lbm_car(prev)) ) { |
658 | |
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) { |
669 | work_to_do = false; |
670 | } else if (lbm_is_ptr(prev)) { |
671 | |
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 |
685 | extern eval_context_t *ctx_running; |
686 | void 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_BIT)) { |
| 10 | | Assuming the condition is false | |
|
| 11 | | Assuming the condition is false | |
|
| |
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 | |
|
| |
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_FIRST && |
| 15 | | Assuming 't_ptr' is < LBM_NON_CONS_POINTER_TYPE_FIRST | |
|
709 | t_ptr <= LBM_NON_CONS_POINTER_TYPE_LAST) continue; |
710 | |
711 | if (cell->car == ENC_SYM_CONT) { |
| 16 | | Assuming the condition is true | |
|
| |
712 | 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 | |
|
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_INTERNAL) == LBM_CONTINUATION_INTERNAL)) { |
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; |
731 | } |
732 | } |
733 | #endif |
734 | |
735 | |
736 | void 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); |
743 | lbm_cons_t *b = lbm_ref_cell(c->car); |
744 | b->cdr = lbm_set_gc_mark(b->cdr); |
745 | lbm_gc_mark_phase(b->cdr); |
746 | lbm_heap_state.gc_marked +=2; |
747 | curr = c->cdr; |
748 | } |
749 | } |
750 | |
751 | |
752 | void 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_FIRST && |
758 | pt_t <= LBM_POINTER_TYPE_LAST && |
759 | pt_v < lbm_heap_state.heap_size) { |
760 | lbm_gc_mark_phase(aux_data[i]); |
761 | } |
762 | } |
763 | } |
764 | } |
765 | |
766 | void 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 | |
773 | int 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 | |
782 | |
783 | if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL) { |
784 | switch(lbm_dec_sym(heap[i].cdr)) { |
785 | |
786 | case SYM_IND_I_TYPE: |
787 | case SYM_IND_U_TYPE: |
788 | case SYM_IND_F_TYPE: |
789 | lbm_memory_free((lbm_uint*)heap[i].car); |
790 | break; |
791 | case SYM_ARRAY_TYPE:{ |
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_TYPE:{ |
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_TYPE: { |
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 | |
816 | lbm_uint addr = lbm_enc_cons_ptr(i); |
817 | |
818 | |
819 | heap[i].car = ENC_SYM_RECOVERED; |
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 | |
829 | void 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 | |
836 | lbm_value lbm_cons(lbm_value car, lbm_value cdr) { |
837 | return lbm_heap_allocate_cell(LBM_TYPE_CONS, car, cdr); |
838 | } |
839 | |
840 | lbm_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_SYMBOL && |
| 20 | | Assuming the condition is true | |
|
| |
848 | lbm_dec_sym(c) == SYM_NIL) { |
| 21 | | Assuming the condition is true | |
|
849 | return ENC_SYM_NIL; |
| |
850 | } |
851 | |
852 | return ENC_SYM_TERROR; |
853 | } |
854 | |
855 | lbm_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_NIL) { |
865 | return tmp; |
866 | } |
867 | } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL) { |
868 | return c; |
869 | } |
870 | return ENC_SYM_TERROR; |
871 | } |
872 | |
873 | |
874 | lbm_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_NIL) { |
884 | return tmp; |
885 | } |
886 | } else if (lbm_is_symbol(c) && lbm_dec_sym(c) == SYM_NIL) { |
887 | return c; |
888 | } |
889 | return ENC_SYM_TERROR; |
890 | } |
891 | |
892 | lbm_value lbm_cdr(lbm_value c){ |
893 | |
894 | if (lbm_type_of(c) == LBM_TYPE_SYMBOL && |
895 | lbm_dec_sym(c) == SYM_NIL) { |
896 | return ENC_SYM_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; |
904 | } |
905 | |
906 | lbm_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_NIL) { |
915 | return ENC_SYM_NIL; |
916 | } |
917 | return ENC_SYM_TERROR; |
918 | } |
919 | |
920 | int lbm_set_car(lbm_value c, lbm_value v) { |
921 | int r = 0; |
922 | |
923 | if (lbm_type_of(c) == LBM_TYPE_CONS) { |
924 | lbm_cons_t *cell = lbm_ref_cell(c); |
925 | cell->car = v; |
926 | r = 1; |
927 | } |
928 | return r; |
929 | } |
930 | |
931 | int 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 | |
941 | int 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 | |
953 | lbm_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 | |
964 | |
965 | unsigned int lbm_list_length_pred(lbm_value c, bool *pres, bool (*pred)(lbm_value)) { |
966 | bool res = true; |
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 | |
979 | lbm_value lbm_list_reverse(lbm_value list) { |
980 | if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
981 | return list; |
982 | } |
983 | |
984 | lbm_value curr = list; |
985 | |
986 | lbm_value new_list = ENC_SYM_NIL; |
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_SYMBOL) { |
991 | return ENC_SYM_MERROR; |
992 | } |
993 | curr = lbm_cdr(curr); |
994 | } |
995 | return new_list; |
996 | } |
997 | |
998 | lbm_value lbm_list_destructive_reverse(lbm_value list) { |
999 | if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
1000 | return list; |
1001 | } |
1002 | lbm_value curr = list; |
1003 | lbm_value last_cell = ENC_SYM_NIL; |
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 | |
1015 | lbm_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; |
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 | |
1040 | |
1041 | lbm_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_CONS) { |
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; |
1055 | } |
1056 | |
1057 | lbm_value lbm_list_drop(unsigned int n, lbm_value ls) { |
1058 | lbm_value curr = ls; |
1059 | while (lbm_type_of_functional(curr) == LBM_TYPE_CONS && |
1060 | n > 0) { |
1061 | curr = lbm_cdr(curr); |
1062 | n --; |
1063 | } |
1064 | return curr; |
1065 | } |
1066 | |
1067 | lbm_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; |
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; |
1085 | } |
1086 | } |
1087 | |
1088 | |
1089 | |
1090 | |
1091 | |
1092 | |
1093 | int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){ |
1094 | |
1095 | lbm_array_header_t *array = NULL; |
1096 | |
1097 | array = (lbm_array_header_t*)lbm_memory_allocate(sizeof(lbm_array_header_t) / sizeof(lbm_uint)); |
1098 | |
1099 | if (array == NULL) { |
1100 | *res = ENC_SYM_MERROR; |
1101 | return 0; |
1102 | } |
1103 | |
1104 | array->data = (lbm_uint*)lbm_malloc(size); |
1105 | |
1106 | if (array->data == NULL) { |
1107 | lbm_memory_free((lbm_uint*)array); |
1108 | *res = ENC_SYM_MERROR; |
1109 | return 0; |
1110 | } |
1111 | memset(array->data, 0, size); |
1112 | array->size = size; |
1113 | |
1114 | |
1115 | lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_ARRAY, (lbm_uint) array, ENC_SYM_ARRAY_TYPE); |
1116 | |
1117 | *res = cell; |
1118 | |
1119 | if (lbm_type_of(cell) == LBM_TYPE_SYMBOL) { |
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 | |
1131 | |
1132 | int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) { |
1133 | |
1134 | lbm_array_header_t *array = NULL; |
1135 | lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE); |
1136 | |
1137 | if (lbm_type_of(cell) == LBM_TYPE_SYMBOL) { |
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) { |
1145 | *value = ENC_SYM_MERROR; |
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_ARRAY); |
1155 | *value = cell; |
1156 | return 1; |
1157 | } |
1158 | |
1159 | lbm_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) { |
1165 | return r; |
1166 | } |
1167 | r = (lbm_int)header->size; |
1168 | } |
1169 | return r; |
1170 | } |
1171 | |
1172 | const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) { |
1173 | uint8_t *r = NULL; |
1174 | if (lbm_is_array_r(arr)) { |
1175 | lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr); |
1176 | if (header == NULL) { |
1177 | return r; |
1178 | } |
1179 | r = (uint8_t*)header->data; |
1180 | } |
1181 | return r; |
1182 | } |
1183 | |
1184 | uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) { |
1185 | uint8_t *r = NULL; |
1186 | if (lbm_is_array_rw(arr)) { |
1187 | lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr); |
1188 | if (header == NULL) { |
1189 | return r; |
1190 | } |
1191 | r = (uint8_t*)header->data; |
1192 | } |
1193 | return r; |
1194 | } |
1195 | |
1196 | |
1197 | |
1198 | |
1199 | |
1200 | |
1201 | |
1202 | |
1203 | |
1204 | |
1205 | |
1206 | |
1207 | |
1208 | |
1209 | |
1210 | |
1211 | |
1212 | |
1213 | |
1214 | int 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) { |
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_CONS); |
1227 | lbm_set_car(arr, ENC_SYM_NIL); |
1228 | lbm_set_cdr(arr, ENC_SYM_NIL); |
1229 | r = 1; |
1230 | } |
1231 | |
1232 | return r; |
1233 | } |
1234 | |
1235 | lbm_uint lbm_size_of(lbm_type t) { |
1236 | lbm_uint s = 0; |
1237 | switch(t) { |
1238 | case LBM_TYPE_BYTE: |
1239 | s = 1; |
1240 | break; |
1241 | case LBM_TYPE_I: |
1242 | case LBM_TYPE_U: |
1243 | case LBM_TYPE_SYMBOL: |
1244 | s = sizeof(lbm_uint); |
1245 | break; |
1246 | case LBM_TYPE_I32: |
1247 | case LBM_TYPE_U32: |
1248 | case LBM_TYPE_FLOAT: |
1249 | s = 4; |
1250 | break; |
1251 | case LBM_TYPE_I64: |
1252 | case LBM_TYPE_U64: |
1253 | case LBM_TYPE_DOUBLE: |
1254 | s = 8; |
1255 | break; |
1256 | } |
1257 | return s; |
1258 | } |
1259 | |
1260 | static bool dummy_flash_write(lbm_uint ix, lbm_uint val) { |
1261 | (void)ix; |
1262 | (void)val; |
1263 | return false; |
1264 | } |
1265 | |
1266 | static const_heap_write_fun const_heap_write = dummy_flash_write; |
1267 | |
1268 | int 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 = true; |
1278 | } |
1279 | |
1280 | if (!lbm_mark_mutex_initialized) { |
1281 | mutex_init(&lbm_mark_mutex); |
1282 | lbm_mark_mutex_initialized = true; |
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 | |
1293 | lbm_heaps[1] = (lbm_cons_t*)addr; |
1294 | return 1; |
1295 | } |
1296 | |
1297 | lbm_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 | |
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 | |
1309 | lbm_value cell = lbm_const_heap_state->next; |
1310 | lbm_const_heap_state->next += 2; |
1311 | *res = (cell << LBM_ADDRESS_SHIFT) | LBM_PTR_BIT | LBM_TYPE_CONS | LBM_PTR_TO_CONSTANT_BIT; |
1312 | r = LBM_FLASH_WRITE_OK; |
1313 | } |
1314 | mutex_unlock(&lbm_const_heap_mutex); |
1315 | return r; |
1316 | } |
1317 | |
1318 | lbm_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 | |
1337 | lbm_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 | |
1344 | lbm_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 | |
1351 | lbm_uint lbm_flash_memory_usage(void) { |
1352 | return lbm_const_heap_state->next; |
1353 | } |