GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
Copyright 2018, 2020, 2022 - 2025 Joel Svensson svenssonjoel@yahoo.se |
||
3 |
2022 Benjamin Vedder |
||
4 |
|||
5 |
This program is free software: you can redistribute it and/or modify |
||
6 |
it under the terms of the GNU General Public License as published by |
||
7 |
the Free Software Foundation, either version 3 of the License, or |
||
8 |
(at your option) any later version. |
||
9 |
|||
10 |
This program is distributed in the hope that it will be useful, |
||
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 |
GNU General Public License for more details. |
||
14 |
|||
15 |
You should have received a copy of the GNU General Public License |
||
16 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
17 |
*/ |
||
18 |
|||
19 |
#include <stdio.h> |
||
20 |
#include <stdlib.h> |
||
21 |
#include <stdint.h> |
||
22 |
#include <stdarg.h> |
||
23 |
#include <inttypes.h> |
||
24 |
#include <lbm_memory.h> |
||
25 |
#include <lbm_custom_type.h> |
||
26 |
#include <lbm_defrag_mem.h> |
||
27 |
#include <lbm_image.h> |
||
28 |
|||
29 |
|||
30 |
#include "heap.h" |
||
31 |
#include "symrepr.h" |
||
32 |
#include "stack.h" |
||
33 |
#include "lbm_channel.h" |
||
34 |
#include "platform_mutex.h" |
||
35 |
#include "eval_cps.h" |
||
36 |
#ifdef VISUALIZE_HEAP |
||
37 |
#include "heap_vis.h" |
||
38 |
#endif |
||
39 |
|||
40 |
72136448 |
static inline lbm_value lbm_set_gc_mark(lbm_value x) { |
|
41 |
72136448 |
return x | LBM_GC_MARKED; |
|
42 |
} |
||
43 |
71939032 |
static inline lbm_value lbm_clr_gc_mark(lbm_value x) { |
|
44 |
71939032 |
return x & ~LBM_GC_MASK; |
|
45 |
} |
||
46 |
|||
47 |
1484464822 |
static inline bool lbm_get_gc_mark(lbm_value x) { |
|
48 |
1484464822 |
return x & LBM_GC_MASK; |
|
49 |
} |
||
50 |
|||
51 |
static inline void gc_mark(lbm_value c) { |
||
52 |
//c must be a cons cell. |
||
53 |
lbm_cons_t *cell = lbm_ref_cell(c); |
||
54 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
||
55 |
} |
||
56 |
|||
57 |
static inline bool gc_marked(lbm_value c) { |
||
58 |
lbm_cons_t *cell = lbm_ref_cell(c); |
||
59 |
return lbm_get_gc_mark(cell->cdr); |
||
60 |
} |
||
61 |
|||
62 |
static inline void gc_clear_mark(lbm_value c) { |
||
63 |
//c must be a cons cell. |
||
64 |
lbm_cons_t *cell = lbm_ref_cell(c); |
||
65 |
cell->cdr = lbm_clr_gc_mark(cell->cdr); |
||
66 |
} |
||
67 |
|||
68 |
// flag is the same bit as mark, but in car |
||
69 |
static inline bool lbm_get_gc_flag(lbm_value x) { |
||
70 |
return x & LBM_GC_MARKED; |
||
71 |
} |
||
72 |
|||
73 |
static inline lbm_value lbm_set_gc_flag(lbm_value x) { |
||
74 |
return x | LBM_GC_MARKED; |
||
75 |
} |
||
76 |
|||
77 |
static inline lbm_value lbm_clr_gc_flag(lbm_value x) { |
||
78 |
return x & ~LBM_GC_MASK; |
||
79 |
} |
||
80 |
|||
81 |
|||
82 |
lbm_heap_state_t lbm_heap_state; |
||
83 |
|||
84 |
lbm_const_heap_t *lbm_const_heap_state; |
||
85 |
|||
86 |
lbm_cons_t *lbm_heaps[2] = {NULL, NULL}; |
||
87 |
|||
88 |
static mutex_t lbm_const_heap_mutex; |
||
89 |
static bool lbm_const_heap_mutex_initialized = false; |
||
90 |
|||
91 |
static mutex_t lbm_mark_mutex; |
||
92 |
static bool lbm_mark_mutex_initialized = false; |
||
93 |
|||
94 |
#ifdef USE_GC_PTR_REV |
||
95 |
void lbm_gc_lock(void) { |
||
96 |
mutex_lock(&lbm_mark_mutex); |
||
97 |
} |
||
98 |
void lbm_gc_unlock(void) { |
||
99 |
mutex_unlock(&lbm_mark_mutex); |
||
100 |
} |
||
101 |
#else |
||
102 |
void lbm_gc_lock(void) { |
||
103 |
} |
||
104 |
void lbm_gc_unlock(void) { |
||
105 |
} |
||
106 |
#endif |
||
107 |
|||
108 |
/****************************************************/ |
||
109 |
/* ENCODERS DECODERS */ |
||
110 |
|||
111 |
2840478 |
lbm_value lbm_enc_i32(int32_t x) { |
|
112 |
#ifndef LBM64 |
||
113 |
2840478 |
lbm_value i = lbm_cons((lbm_uint)x, ENC_SYM_RAW_I_TYPE); |
|
114 |
✓✓ | 2840478 |
if (lbm_type_of(i) == LBM_TYPE_SYMBOL) return i; |
115 |
2839084 |
return lbm_set_ptr_type(i, LBM_TYPE_I32); |
|
116 |
#else |
||
117 |
return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_I32; |
||
118 |
#endif |
||
119 |
} |
||
120 |
|||
121 |
3679914 |
lbm_value lbm_enc_u32(uint32_t x) { |
|
122 |
#ifndef LBM64 |
||
123 |
3679914 |
lbm_value u = lbm_cons(x, ENC_SYM_RAW_U_TYPE); |
|
124 |
✓✓ | 3679914 |
if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
125 |
3679042 |
return lbm_set_ptr_type(u, LBM_TYPE_U32); |
|
126 |
#else |
||
127 |
return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_U32; |
||
128 |
#endif |
||
129 |
} |
||
130 |
|||
131 |
229868948 |
lbm_value lbm_enc_float(float x) { |
|
132 |
#ifndef LBM64 |
||
133 |
lbm_uint t; |
||
134 |
229868948 |
memcpy(&t, &x, sizeof(lbm_float)); |
|
135 |
229868948 |
lbm_value f = lbm_cons(t, ENC_SYM_RAW_F_TYPE); |
|
136 |
✓✓ | 229868948 |
if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f; |
137 |
229725312 |
return lbm_set_ptr_type(f, LBM_TYPE_FLOAT); |
|
138 |
#else |
||
139 |
lbm_uint t = 0; |
||
140 |
memcpy(&t, &x, sizeof(float)); |
||
141 |
return (((lbm_uint)t) << LBM_VAL_SHIFT) | LBM_TYPE_FLOAT; |
||
142 |
#endif |
||
143 |
} |
||
144 |
|||
145 |
#ifndef LBM64 |
||
146 |
8426306 |
static lbm_value enc_64_on_32(uint8_t *source, lbm_uint type_qual, lbm_uint type) { |
|
147 |
8426306 |
lbm_value res = lbm_cons(ENC_SYM_NIL,ENC_SYM_NIL); |
|
148 |
✓✓ | 8426306 |
if (lbm_type_of(res) != LBM_TYPE_SYMBOL) { |
149 |
8423984 |
uint8_t* storage = lbm_malloc(sizeof(uint64_t)); |
|
150 |
✓✓ | 8423984 |
if (storage) { |
151 |
8421356 |
memcpy(storage,source, sizeof(uint64_t)); |
|
152 |
8421356 |
lbm_set_car_and_cdr(res, (lbm_uint)storage, type_qual); |
|
153 |
8421356 |
res = lbm_set_ptr_type(res, type); |
|
154 |
} else { |
||
155 |
2628 |
res = ENC_SYM_MERROR; |
|
156 |
} |
||
157 |
} |
||
158 |
8426306 |
return res; |
|
159 |
} |
||
160 |
#endif |
||
161 |
|||
162 |
4491380 |
lbm_value lbm_enc_i64(int64_t x) { |
|
163 |
#ifndef LBM64 |
||
164 |
4491380 |
return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_I_TYPE, LBM_TYPE_I64); |
|
165 |
#else |
||
166 |
lbm_value u = lbm_cons((uint64_t)x, ENC_SYM_RAW_I_TYPE); |
||
167 |
if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
||
168 |
return lbm_set_ptr_type(u, LBM_TYPE_I64); |
||
169 |
#endif |
||
170 |
} |
||
171 |
|||
172 |
3369218 |
lbm_value lbm_enc_u64(uint64_t x) { |
|
173 |
#ifndef LBM64 |
||
174 |
3369218 |
return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_U_TYPE, LBM_TYPE_U64); |
|
175 |
#else |
||
176 |
lbm_value u = lbm_cons(x, ENC_SYM_RAW_U_TYPE); |
||
177 |
if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
||
178 |
return lbm_set_ptr_type(u, LBM_TYPE_U64); |
||
179 |
#endif |
||
180 |
} |
||
181 |
|||
182 |
565708 |
lbm_value lbm_enc_double(double x) { |
|
183 |
#ifndef LBM64 |
||
184 |
565708 |
return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_F_TYPE, LBM_TYPE_DOUBLE); |
|
185 |
#else |
||
186 |
lbm_uint t; |
||
187 |
memcpy(&t, &x, sizeof(double)); |
||
188 |
lbm_value f = lbm_cons(t, ENC_SYM_RAW_F_TYPE); |
||
189 |
if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f; |
||
190 |
return lbm_set_ptr_type(f, LBM_TYPE_DOUBLE); |
||
191 |
#endif |
||
192 |
} |
||
193 |
|||
194 |
// Type specific (as opposed to the dec_as_X) functions |
||
195 |
// should only be run on values KNOWN to represent a value of the type |
||
196 |
// that the decoder decodes. |
||
197 |
|||
198 |
333511290 |
float lbm_dec_float(lbm_value x) { |
|
199 |
#ifndef LBM64 |
||
200 |
float f_tmp; |
||
201 |
333511290 |
lbm_uint tmp = lbm_car(x); |
|
202 |
333511290 |
memcpy(&f_tmp, &tmp, sizeof(float)); |
|
203 |
333511290 |
return f_tmp; |
|
204 |
#else |
||
205 |
uint32_t tmp = (uint32_t)(x >> LBM_VAL_SHIFT); |
||
206 |
float f_tmp; |
||
207 |
memcpy(&f_tmp, &tmp, sizeof(float)); |
||
208 |
return f_tmp; |
||
209 |
#endif |
||
210 |
} |
||
211 |
|||
212 |
564784 |
double lbm_dec_double(lbm_value x) { |
|
213 |
#ifndef LBM64 |
||
214 |
564784 |
double d = 0.0; |
|
215 |
✓✗ | 564784 |
if (lbm_is_ptr(x)) { |
216 |
564784 |
uint32_t *data = (uint32_t*)lbm_ref_cell(x)->car; |
|
217 |
564784 |
memcpy(&d, data, sizeof(double)); |
|
218 |
} |
||
219 |
564784 |
return d; |
|
220 |
#else |
||
221 |
double f_tmp; |
||
222 |
lbm_uint tmp = lbm_car(x); |
||
223 |
memcpy(&f_tmp, &tmp, sizeof(double)); |
||
224 |
return f_tmp; |
||
225 |
#endif |
||
226 |
} |
||
227 |
|||
228 |
7010126 |
uint64_t lbm_dec_u64(lbm_value x) { |
|
229 |
#ifndef LBM64 |
||
230 |
7010126 |
uint64_t u = 0; |
|
231 |
✓✗ | 7010126 |
if (lbm_is_ptr(x)) { |
232 |
7010126 |
uint32_t *data = (uint32_t*)lbm_ref_cell(x)->car; |
|
233 |
7010126 |
memcpy(&u, data, 8); |
|
234 |
} |
||
235 |
7010126 |
return u; |
|
236 |
#else |
||
237 |
return (uint64_t)lbm_car(x); |
||
238 |
#endif |
||
239 |
} |
||
240 |
|||
241 |
9251868 |
int64_t lbm_dec_i64(lbm_value x) { |
|
242 |
#ifndef LBM64 |
||
243 |
9251868 |
int64_t i = 0; |
|
244 |
✓✗ | 9251868 |
if (lbm_is_ptr(x)) { |
245 |
9251868 |
uint32_t *data = (uint32_t*)lbm_ref_cell(x)->car; |
|
246 |
9251868 |
memcpy(&i, data, 8); |
|
247 |
} |
||
248 |
9251868 |
return i; |
|
249 |
#else |
||
250 |
return (int64_t)lbm_car(x); |
||
251 |
#endif |
||
252 |
} |
||
253 |
|||
254 |
791056 |
char *lbm_dec_str(lbm_value val) { |
|
255 |
791056 |
char *res = 0; |
|
256 |
✓✓ | 791056 |
if (lbm_is_array_r(val)) { |
257 |
790860 |
lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(val); |
|
258 |
✓✗ | 790860 |
if (array) { |
259 |
790860 |
res = (char *)array->data; |
|
260 |
} |
||
261 |
} |
||
262 |
791056 |
return res; |
|
263 |
} |
||
264 |
|||
265 |
599354 |
lbm_array_header_t *lbm_dec_array_r(lbm_value val) { |
|
266 |
599354 |
lbm_array_header_t *array = NULL; |
|
267 |
✓✓ | 599354 |
if (lbm_is_array_r(val)) { |
268 |
598010 |
array = (lbm_array_header_t *)lbm_car(val); |
|
269 |
} |
||
270 |
599354 |
return array; |
|
271 |
} |
||
272 |
|||
273 |
59528 |
lbm_array_header_t *lbm_dec_array_rw(lbm_value val) { |
|
274 |
59528 |
lbm_array_header_t *array = NULL; |
|
275 |
✓✓ | 59528 |
if (lbm_is_array_rw(val)) { |
276 |
59444 |
array = (lbm_array_header_t *)lbm_car(val); |
|
277 |
} |
||
278 |
59528 |
return array; |
|
279 |
} |
||
280 |
|||
281 |
lbm_array_header_t *lbm_dec_lisp_array_r(lbm_value val) { |
||
282 |
lbm_array_header_t *array = NULL; |
||
283 |
if (lbm_is_lisp_array_r(val)) { |
||
284 |
array = (lbm_array_header_t *)lbm_car(val); |
||
285 |
} |
||
286 |
return array; |
||
287 |
} |
||
288 |
|||
289 |
lbm_array_header_t *lbm_dec_lisp_array_rw(lbm_value val) { |
||
290 |
lbm_array_header_t *array = NULL; |
||
291 |
if (lbm_is_lisp_array_rw(val)) { |
||
292 |
array = (lbm_array_header_t *)lbm_car(val); |
||
293 |
} |
||
294 |
return array; |
||
295 |
} |
||
296 |
|||
297 |
11225307 |
lbm_char_channel_t *lbm_dec_channel(lbm_value val) { |
|
298 |
11225307 |
lbm_char_channel_t *res = NULL; |
|
299 |
|||
300 |
✓✗ | 11225307 |
if (lbm_type_of(val) == LBM_TYPE_CHANNEL) { |
301 |
11225307 |
res = (lbm_char_channel_t *)lbm_car(val); |
|
302 |
} |
||
303 |
11225307 |
return res; |
|
304 |
} |
||
305 |
|||
306 |
lbm_uint lbm_dec_custom(lbm_value val) { |
||
307 |
lbm_uint res = 0; |
||
308 |
if (lbm_type_of(val) == LBM_TYPE_CUSTOM) { |
||
309 |
res = (lbm_uint)lbm_car(val); |
||
310 |
} |
||
311 |
return res; |
||
312 |
} |
||
313 |
|||
314 |
60900 |
uint8_t lbm_dec_as_char(lbm_value a) { |
|
315 |
60900 |
uint8_t r = 0; |
|
316 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
60900 |
switch (lbm_type_of_functional(a)) { |
317 |
60676 |
case LBM_TYPE_CHAR: |
|
318 |
60676 |
r = (uint8_t)lbm_dec_char(a); break; |
|
319 |
28 |
case LBM_TYPE_I: |
|
320 |
28 |
r = (uint8_t)lbm_dec_i(a); break; |
|
321 |
28 |
case LBM_TYPE_U: |
|
322 |
28 |
r = (uint8_t)lbm_dec_u(a); break; |
|
323 |
28 |
case LBM_TYPE_I32: |
|
324 |
28 |
r = (uint8_t)lbm_dec_i32(a); break; |
|
325 |
28 |
case LBM_TYPE_U32: |
|
326 |
28 |
r = (uint8_t)lbm_dec_u32(a); break; |
|
327 |
28 |
case LBM_TYPE_FLOAT: |
|
328 |
28 |
r = (uint8_t)lbm_dec_float(a); break; |
|
329 |
28 |
case LBM_TYPE_I64: |
|
330 |
28 |
r = (uint8_t)lbm_dec_i64(a); break; |
|
331 |
28 |
case LBM_TYPE_U64: |
|
332 |
28 |
r = (uint8_t)lbm_dec_u64(a); break; |
|
333 |
28 |
case LBM_TYPE_DOUBLE: |
|
334 |
28 |
r = (uint8_t) lbm_dec_double(a); break; |
|
335 |
} |
||
336 |
60900 |
return r; |
|
337 |
} |
||
338 |
|||
339 |
8808544 |
uint32_t lbm_dec_as_u32(lbm_value a) { |
|
340 |
8808544 |
uint32_t r = 0; |
|
341 |
✓✓✓✓ ✓✓✓✓ ✗ |
8808544 |
switch (lbm_type_of_functional(a)) { |
342 |
561938 |
case LBM_TYPE_CHAR: |
|
343 |
561938 |
r = (uint32_t)lbm_dec_char(a); break; |
|
344 |
1639279 |
case LBM_TYPE_I: |
|
345 |
1639279 |
r = (uint32_t)lbm_dec_i(a); break; |
|
346 |
1812055 |
case LBM_TYPE_U: |
|
347 |
1812055 |
r = (uint32_t)lbm_dec_u(a); break; |
|
348 |
4795104 |
case LBM_TYPE_I32: /* fall through */ |
|
349 |
case LBM_TYPE_U32: |
||
350 |
4795104 |
r = (uint32_t)lbm_dec_u32(a); break; |
|
351 |
28 |
case LBM_TYPE_FLOAT: |
|
352 |
28 |
r = (uint32_t)lbm_dec_float(a); break; |
|
353 |
28 |
case LBM_TYPE_I64: |
|
354 |
28 |
r = (uint32_t)lbm_dec_i64(a); break; |
|
355 |
84 |
case LBM_TYPE_U64: |
|
356 |
84 |
r = (uint32_t)lbm_dec_u64(a); break; |
|
357 |
28 |
case LBM_TYPE_DOUBLE: |
|
358 |
28 |
r = (uint32_t)lbm_dec_double(a); break; |
|
359 |
} |
||
360 |
8808544 |
return r; |
|
361 |
} |
||
362 |
|||
363 |
242350062 |
int32_t lbm_dec_as_i32(lbm_value a) { |
|
364 |
242350062 |
int32_t r = 0; |
|
365 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
242350062 |
switch (lbm_type_of_functional(a)) { |
366 |
6130040 |
case LBM_TYPE_CHAR: |
|
367 |
6130040 |
r = (int32_t)lbm_dec_char(a); break; |
|
368 |
232537490 |
case LBM_TYPE_I: |
|
369 |
232537490 |
r = (int32_t)lbm_dec_i(a); break; |
|
370 |
8196 |
case LBM_TYPE_U: |
|
371 |
8196 |
r = (int32_t)lbm_dec_u(a); break; |
|
372 |
3674140 |
case LBM_TYPE_I32: |
|
373 |
3674140 |
r = (int32_t)lbm_dec_i32(a); break; |
|
374 |
28 |
case LBM_TYPE_U32: |
|
375 |
28 |
r = (int32_t)lbm_dec_u32(a); break; |
|
376 |
28 |
case LBM_TYPE_FLOAT: |
|
377 |
28 |
r = (int32_t)lbm_dec_float(a); break; |
|
378 |
56 |
case LBM_TYPE_I64: |
|
379 |
56 |
r = (int32_t)lbm_dec_i64(a); break; |
|
380 |
56 |
case LBM_TYPE_U64: |
|
381 |
56 |
r = (int32_t)lbm_dec_u64(a); break; |
|
382 |
28 |
case LBM_TYPE_DOUBLE: |
|
383 |
28 |
r = (int32_t) lbm_dec_double(a); break; |
|
384 |
} |
||
385 |
242350062 |
return r; |
|
386 |
} |
||
387 |
|||
388 |
6728328 |
int64_t lbm_dec_as_i64(lbm_value a) { |
|
389 |
6728328 |
int64_t r = 0; |
|
390 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
6728328 |
switch (lbm_type_of_functional(a)) { |
391 |
562230 |
case LBM_TYPE_CHAR: |
|
392 |
562230 |
r = (int64_t)lbm_dec_char(a); break; |
|
393 |
1402474 |
case LBM_TYPE_I: |
|
394 |
1402474 |
r = (int64_t)lbm_dec_i(a); break; |
|
395 |
168 |
case LBM_TYPE_U: |
|
396 |
168 |
r = (int64_t)lbm_dec_u(a); break; |
|
397 |
168 |
case LBM_TYPE_I32: |
|
398 |
168 |
r = (int64_t)lbm_dec_i32(a); break; |
|
399 |
168 |
case LBM_TYPE_U32: |
|
400 |
168 |
r = (int64_t)lbm_dec_u32(a); break; |
|
401 |
56 |
case LBM_TYPE_FLOAT: |
|
402 |
56 |
r = (int64_t)lbm_dec_float(a); break; |
|
403 |
4762896 |
case LBM_TYPE_I64: |
|
404 |
4762896 |
r = (int64_t)lbm_dec_i64(a); break; |
|
405 |
112 |
case LBM_TYPE_U64: |
|
406 |
112 |
r = (int64_t)lbm_dec_u64(a); break; |
|
407 |
56 |
case LBM_TYPE_DOUBLE: |
|
408 |
56 |
r = (int64_t) lbm_dec_double(a); break; |
|
409 |
} |
||
410 |
6728328 |
return r; |
|
411 |
} |
||
412 |
|||
413 |
4486502 |
uint64_t lbm_dec_as_u64(lbm_value a) { |
|
414 |
4486502 |
uint64_t r = 0; |
|
415 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
4486502 |
switch (lbm_type_of_functional(a)) { |
416 |
562202 |
case LBM_TYPE_CHAR: |
|
417 |
562202 |
r = (uint64_t)lbm_dec_char(a); break; |
|
418 |
280592 |
case LBM_TYPE_I: |
|
419 |
280592 |
r = (uint64_t)lbm_dec_i(a); break; |
|
420 |
168 |
case LBM_TYPE_U: |
|
421 |
168 |
r = (uint64_t)lbm_dec_u(a); break; |
|
422 |
168 |
case LBM_TYPE_I32: |
|
423 |
168 |
r = (uint64_t)lbm_dec_i32(a); break; |
|
424 |
168 |
case LBM_TYPE_U32: |
|
425 |
168 |
r = (uint64_t)lbm_dec_u32(a); break; |
|
426 |
56 |
case LBM_TYPE_FLOAT: |
|
427 |
56 |
r = (uint64_t)lbm_dec_float(a); break; |
|
428 |
168 |
case LBM_TYPE_I64: |
|
429 |
168 |
r = (uint64_t)lbm_dec_i64(a); break; |
|
430 |
3642924 |
case LBM_TYPE_U64: |
|
431 |
3642924 |
r = (uint64_t)lbm_dec_u64(a); break; |
|
432 |
56 |
case LBM_TYPE_DOUBLE: |
|
433 |
56 |
r = (uint64_t)lbm_dec_double(a); break; |
|
434 |
} |
||
435 |
4486502 |
return r; |
|
436 |
} |
||
437 |
|||
438 |
58352 |
lbm_uint lbm_dec_as_uint(lbm_value a) { |
|
439 |
58352 |
lbm_uint r = 0; |
|
440 |
✗✓✗✗ ✗✗✗✗ ✗✗ |
58352 |
switch (lbm_type_of_functional(a)) { |
441 |
case LBM_TYPE_CHAR: |
||
442 |
r = (lbm_uint)lbm_dec_char(a); break; |
||
443 |
58352 |
case LBM_TYPE_I: |
|
444 |
58352 |
r = (lbm_uint)lbm_dec_i(a); break; |
|
445 |
case LBM_TYPE_U: |
||
446 |
r = (lbm_uint)lbm_dec_u(a); break; |
||
447 |
case LBM_TYPE_I32: |
||
448 |
r = (lbm_uint)lbm_dec_i32(a); break; |
||
449 |
case LBM_TYPE_U32: |
||
450 |
r = (lbm_uint)lbm_dec_u32(a); break; |
||
451 |
case LBM_TYPE_FLOAT: |
||
452 |
r = (lbm_uint)lbm_dec_float(a); break; |
||
453 |
case LBM_TYPE_I64: |
||
454 |
r = (lbm_uint)lbm_dec_i64(a); break; |
||
455 |
case LBM_TYPE_U64: |
||
456 |
r = (lbm_uint) lbm_dec_u64(a); break; |
||
457 |
case LBM_TYPE_DOUBLE: |
||
458 |
r = (lbm_uint)lbm_dec_double(a); break; |
||
459 |
} |
||
460 |
58352 |
return r; |
|
461 |
} |
||
462 |
|||
463 |
644 |
lbm_int lbm_dec_as_int(lbm_value a) { |
|
464 |
644 |
lbm_int r = 0; |
|
465 |
✗✓✗✗ ✗✗✗✗ ✗✗ |
644 |
switch (lbm_type_of_functional(a)) { |
466 |
case LBM_TYPE_CHAR: |
||
467 |
r = (lbm_int)lbm_dec_char(a); break; |
||
468 |
644 |
case LBM_TYPE_I: |
|
469 |
644 |
r = (lbm_int)lbm_dec_i(a); break; |
|
470 |
case LBM_TYPE_U: |
||
471 |
r = (lbm_int)lbm_dec_u(a); break; |
||
472 |
case LBM_TYPE_I32: |
||
473 |
r = (lbm_int)lbm_dec_i32(a); break; |
||
474 |
case LBM_TYPE_U32: |
||
475 |
r = (lbm_int)lbm_dec_u32(a); break; |
||
476 |
case LBM_TYPE_FLOAT: |
||
477 |
r = (lbm_int)lbm_dec_float(a); break; |
||
478 |
case LBM_TYPE_I64: |
||
479 |
r = (lbm_int)lbm_dec_i64(a); break; |
||
480 |
case LBM_TYPE_U64: |
||
481 |
r = (lbm_int)lbm_dec_u64(a); break; |
||
482 |
case LBM_TYPE_DOUBLE: |
||
483 |
r = (lbm_int)lbm_dec_double(a); break; |
||
484 |
} |
||
485 |
644 |
return r; |
|
486 |
} |
||
487 |
|||
488 |
375465700 |
float lbm_dec_as_float(lbm_value a) { |
|
489 |
375465700 |
float r = 0; |
|
490 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
375465700 |
switch (lbm_type_of_functional(a)) { |
491 |
103744728 |
case LBM_TYPE_CHAR: |
|
492 |
103744728 |
r = (float)lbm_dec_char(a); break; |
|
493 |
168074742 |
case LBM_TYPE_I: |
|
494 |
168074742 |
r = (float)lbm_dec_i(a); break; |
|
495 |
140 |
case LBM_TYPE_U: |
|
496 |
140 |
r = (float)lbm_dec_u(a); break; |
|
497 |
140 |
case LBM_TYPE_I32: |
|
498 |
140 |
r = (float)lbm_dec_i32(a); break; |
|
499 |
196 |
case LBM_TYPE_U32: |
|
500 |
196 |
r = (float)lbm_dec_u32(a); break; |
|
501 |
103645446 |
case LBM_TYPE_FLOAT: |
|
502 |
103645446 |
r = (float)lbm_dec_float(a); break; |
|
503 |
140 |
case LBM_TYPE_I64: |
|
504 |
140 |
r = (float)lbm_dec_i64(a); break; |
|
505 |
140 |
case LBM_TYPE_U64: |
|
506 |
140 |
r = (float)lbm_dec_u64(a); break; |
|
507 |
28 |
case LBM_TYPE_DOUBLE: |
|
508 |
28 |
r = (float)lbm_dec_double(a); break; |
|
509 |
} |
||
510 |
375465700 |
return r; |
|
511 |
} |
||
512 |
|||
513 |
563944 |
double lbm_dec_as_double(lbm_value a) { |
|
514 |
563944 |
double r = 0; |
|
515 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
563944 |
switch (lbm_type_of_functional(a)) { |
516 |
281168 |
case LBM_TYPE_CHAR: |
|
517 |
281168 |
r = (double)lbm_dec_char(a); break; |
|
518 |
280620 |
case LBM_TYPE_I: |
|
519 |
280620 |
r = (double)lbm_dec_i(a); break; |
|
520 |
140 |
case LBM_TYPE_U: |
|
521 |
140 |
r = (double)lbm_dec_u(a); break; |
|
522 |
140 |
case LBM_TYPE_I32: |
|
523 |
140 |
r = (double)lbm_dec_i32(a); break; |
|
524 |
140 |
case LBM_TYPE_U32: |
|
525 |
140 |
r = (double)lbm_dec_u32(a); break; |
|
526 |
364 |
case LBM_TYPE_FLOAT: |
|
527 |
364 |
r = (double)lbm_dec_float(a); break; |
|
528 |
140 |
case LBM_TYPE_I64: |
|
529 |
140 |
r = (double)lbm_dec_i64(a); break; |
|
530 |
140 |
case LBM_TYPE_U64: |
|
531 |
140 |
r = (double)lbm_dec_u64(a); break; |
|
532 |
1092 |
case LBM_TYPE_DOUBLE: |
|
533 |
1092 |
r = (double)lbm_dec_double(a); break; |
|
534 |
} |
||
535 |
563944 |
return r; |
|
536 |
} |
||
537 |
|||
538 |
/****************************************************/ |
||
539 |
/* HEAP MANAGEMENT */ |
||
540 |
|||
541 |
21924 |
static int generate_freelist(size_t num_cells) { |
|
542 |
21924 |
size_t i = 0; |
|
543 |
|||
544 |
✗✓ | 21924 |
if (!lbm_heap_state.heap) return 0; |
545 |
|||
546 |
21924 |
lbm_heap_state.freelist = lbm_enc_cons_ptr(0); |
|
547 |
|||
548 |
lbm_cons_t *t; |
||
549 |
|||
550 |
// Add all cells to free list |
||
551 |
✓✓ | 203655168 |
for (i = 1; i < num_cells; i ++) { |
552 |
203633244 |
t = lbm_ref_cell(lbm_enc_cons_ptr(i-1)); |
|
553 |
203633244 |
t->car = ENC_SYM_RECOVERED; // all cars in free list are "RECOVERED" |
|
554 |
203633244 |
t->cdr = lbm_enc_cons_ptr(i); |
|
555 |
} |
||
556 |
|||
557 |
// Replace the incorrect pointer at the last cell. |
||
558 |
21924 |
t = lbm_ref_cell(lbm_enc_cons_ptr(num_cells-1)); |
|
559 |
21924 |
t->cdr = ENC_SYM_NIL; |
|
560 |
|||
561 |
21924 |
return 1; |
|
562 |
} |
||
563 |
|||
564 |
614552 |
void lbm_nil_freelist(void) { |
|
565 |
614552 |
lbm_heap_state.freelist = ENC_SYM_NIL; |
|
566 |
614552 |
lbm_heap_state.num_alloc = lbm_heap_state.heap_size; |
|
567 |
614552 |
} |
|
568 |
|||
569 |
21924 |
static void heap_init_state(lbm_cons_t *addr, lbm_uint num_cells, |
|
570 |
lbm_uint* gc_stack_storage, lbm_uint gc_stack_size) { |
||
571 |
21924 |
lbm_heap_state.heap = addr; |
|
572 |
21924 |
lbm_heap_state.heap_bytes = (unsigned int)(num_cells * sizeof(lbm_cons_t)); |
|
573 |
21924 |
lbm_heap_state.heap_size = num_cells; |
|
574 |
|||
575 |
21924 |
lbm_stack_create(&lbm_heap_state.gc_stack, gc_stack_storage, gc_stack_size); |
|
576 |
|||
577 |
21924 |
lbm_heap_state.num_alloc = 0; |
|
578 |
21924 |
lbm_heap_state.num_alloc_arrays = 0; |
|
579 |
21924 |
lbm_heap_state.gc_num = 0; |
|
580 |
21924 |
lbm_heap_state.gc_marked = 0; |
|
581 |
21924 |
lbm_heap_state.gc_recovered = 0; |
|
582 |
21924 |
lbm_heap_state.gc_recovered_arrays = 0; |
|
583 |
21924 |
lbm_heap_state.gc_least_free = num_cells; |
|
584 |
21924 |
lbm_heap_state.gc_last_free = num_cells; |
|
585 |
21924 |
} |
|
586 |
|||
587 |
614552 |
void lbm_heap_new_freelist_length(void) { |
|
588 |
614552 |
lbm_uint l = lbm_heap_state.heap_size - lbm_heap_state.num_alloc; |
|
589 |
614552 |
lbm_heap_state.gc_last_free = l; |
|
590 |
✓✓ | 614552 |
if (l < lbm_heap_state.gc_least_free) |
591 |
4018 |
lbm_heap_state.gc_least_free = l; |
|
592 |
614552 |
} |
|
593 |
|||
594 |
21924 |
int lbm_heap_init(lbm_cons_t *addr, lbm_uint num_cells, |
|
595 |
lbm_uint gc_stack_size) { |
||
596 |
|||
597 |
✗✓ | 21924 |
if (((uintptr_t)addr % 8) != 0) return 0; |
598 |
|||
599 |
21924 |
memset(addr,0, sizeof(lbm_cons_t) * num_cells); |
|
600 |
|||
601 |
21924 |
lbm_uint *gc_stack_storage = (lbm_uint*)lbm_malloc(gc_stack_size * sizeof(lbm_uint)); |
|
602 |
✗✓ | 21924 |
if (gc_stack_storage == NULL) return 0; |
603 |
|||
604 |
21924 |
heap_init_state(addr, num_cells, |
|
605 |
gc_stack_storage, gc_stack_size); |
||
606 |
|||
607 |
21924 |
lbm_heaps[0] = addr; |
|
608 |
|||
609 |
21924 |
return generate_freelist(num_cells); |
|
610 |
} |
||
611 |
|||
612 |
|||
613 |
555405679 |
lbm_value lbm_heap_allocate_cell(lbm_type ptr_type, lbm_value car, lbm_value cdr) { |
|
614 |
lbm_value r; |
||
615 |
555405679 |
lbm_value cell = lbm_heap_state.freelist; |
|
616 |
✓✓ | 555405679 |
if (cell) { |
617 |
555254229 |
lbm_uint heap_ix = lbm_dec_ptr(cell); |
|
618 |
555254229 |
lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr; |
|
619 |
555254229 |
lbm_heap_state.num_alloc++; |
|
620 |
555254229 |
lbm_heap_state.heap[heap_ix].car = car; |
|
621 |
555254229 |
lbm_heap_state.heap[heap_ix].cdr = cdr; |
|
622 |
555254229 |
r = lbm_set_ptr_type(cell, ptr_type); |
|
623 |
} else { |
||
624 |
151450 |
r = ENC_SYM_MERROR; |
|
625 |
} |
||
626 |
555405679 |
return r; |
|
627 |
} |
||
628 |
|||
629 |
1255352 |
lbm_value lbm_heap_allocate_list(lbm_uint n) { |
|
630 |
✓✓ | 1255352 |
if (n == 0) return ENC_SYM_NIL; |
631 |
✓✓ | 1252048 |
if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
632 |
|||
633 |
1250624 |
lbm_value curr = lbm_heap_state.freelist; |
|
634 |
1250624 |
lbm_value res = curr; |
|
635 |
✓✗ | 1250624 |
if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
636 |
|||
637 |
1250624 |
lbm_cons_t *c_cell = NULL; |
|
638 |
1250624 |
lbm_uint count = 0; |
|
639 |
do { |
||
640 |
6466096 |
c_cell = lbm_ref_cell(curr); |
|
641 |
6466096 |
c_cell->car = ENC_SYM_NIL; |
|
642 |
6466096 |
curr = c_cell->cdr; |
|
643 |
6466096 |
count ++; |
|
644 |
✓✓ | 6466096 |
} while (count < n); |
645 |
1250624 |
lbm_heap_state.freelist = curr; |
|
646 |
1250624 |
c_cell->cdr = ENC_SYM_NIL; |
|
647 |
1250624 |
lbm_heap_state.num_alloc+=count; |
|
648 |
1250624 |
return res; |
|
649 |
} |
||
650 |
return ENC_SYM_FATAL_ERROR; |
||
651 |
} |
||
652 |
|||
653 |
21963620 |
lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) { |
|
654 |
✗✓ | 21963620 |
if (n == 0) return ENC_SYM_NIL; |
655 |
✓✓ | 21963620 |
if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
656 |
|||
657 |
21930426 |
lbm_value curr = lbm_heap_state.freelist; |
|
658 |
21930426 |
lbm_value res = curr; |
|
659 |
✓✗ | 21930426 |
if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
660 |
|||
661 |
21930426 |
lbm_cons_t *c_cell = NULL; |
|
662 |
21930426 |
unsigned int count = 0; |
|
663 |
do { |
||
664 |
44144572 |
c_cell = lbm_ref_cell(curr); |
|
665 |
44144572 |
c_cell->car = va_arg(valist, lbm_value); |
|
666 |
44144572 |
curr = c_cell->cdr; |
|
667 |
44144572 |
count ++; |
|
668 |
✓✓ | 44144572 |
} while (count < n); |
669 |
21930426 |
lbm_heap_state.freelist = curr; |
|
670 |
21930426 |
c_cell->cdr = ENC_SYM_NIL; |
|
671 |
21930426 |
lbm_heap_state.num_alloc+=count; |
|
672 |
21930426 |
return res; |
|
673 |
} |
||
674 |
return ENC_SYM_FATAL_ERROR; |
||
675 |
} |
||
676 |
|||
677 |
21963620 |
lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) { |
|
678 |
va_list valist; |
||
679 |
21963620 |
va_start(valist, n); |
|
680 |
21963620 |
lbm_value r = lbm_heap_allocate_list_init_va(n, valist); |
|
681 |
21963620 |
va_end(valist); |
|
682 |
21963620 |
return r; |
|
683 |
} |
||
684 |
|||
685 |
lbm_uint lbm_heap_num_allocated(void) { |
||
686 |
return lbm_heap_state.num_alloc; |
||
687 |
} |
||
688 |
lbm_uint lbm_heap_size(void) { |
||
689 |
return lbm_heap_state.heap_size; |
||
690 |
} |
||
691 |
|||
692 |
lbm_uint lbm_heap_size_bytes(void) { |
||
693 |
return lbm_heap_state.heap_bytes; |
||
694 |
} |
||
695 |
|||
696 |
252 |
void lbm_get_heap_state(lbm_heap_state_t *res) { |
|
697 |
252 |
*res = lbm_heap_state; |
|
698 |
252 |
} |
|
699 |
|||
700 |
lbm_uint lbm_get_gc_stack_max(void) { |
||
701 |
return lbm_get_max_stack(&lbm_heap_state.gc_stack); |
||
702 |
} |
||
703 |
|||
704 |
lbm_uint lbm_get_gc_stack_size(void) { |
||
705 |
return lbm_heap_state.gc_stack.size; |
||
706 |
} |
||
707 |
|||
708 |
static inline void value_assign(lbm_value *a, lbm_value b) { |
||
709 |
lbm_value a_old = *a & LBM_GC_MASK; |
||
710 |
*a = a_old | (b & ~LBM_GC_MASK); |
||
711 |
} |
||
712 |
|||
713 |
#ifdef LBM_USE_GC_PTR_REV |
||
714 |
/* ************************************************************ |
||
715 |
Deutch-Schorr-Waite (DSW) pointer reversal GC for 2-ptr cells |
||
716 |
with a hack-solution for the lisp-array case (n-ptr cells). |
||
717 |
|||
718 |
DSW visits each branch node 3 times compared to 2 times for |
||
719 |
the stack based recursive mark. |
||
720 |
Where the stack based recursive mark performs a stack push/pop, |
||
721 |
DSW rearranges the, current, prev, next and a ptr field on |
||
722 |
the heap. |
||
723 |
|||
724 |
DSW changes the structure of the heap and it introduces an |
||
725 |
invalid pointer (LBM_PTR_NULL) temporarily during marking. |
||
726 |
Since the heap will be "messed up" while marking, a mutex |
||
727 |
is introuded to keep other processes out of the heap while |
||
728 |
marking. |
||
729 |
|||
730 |
TODO: See if the extra index field in arrays can be used |
||
731 |
to mark arrays without resorting to recursive mark calls. |
||
732 |
*/ |
||
733 |
|||
734 |
|||
735 |
void lbm_gc_mark_phase_nm(lbm_value root) { |
||
736 |
bool work_to_do = true; |
||
737 |
if (!lbm_is_ptr(root)) return; |
||
738 |
|||
739 |
lbm_value curr = root; |
||
740 |
lbm_value prev = lbm_enc_cons_ptr(LBM_PTR_NULL); |
||
741 |
|||
742 |
while (work_to_do) { |
||
743 |
// follow leftwards pointers |
||
744 |
while (lbm_is_ptr(curr) && |
||
745 |
(lbm_dec_ptr(curr) != LBM_PTR_NULL) && |
||
746 |
((curr & LBM_PTR_TO_CONSTANT_BIT) == 0) && |
||
747 |
!lbm_get_gc_mark(lbm_cdr(curr))) { |
||
748 |
// Mark the cell if not a constant cell |
||
749 |
lbm_cons_t *cell = lbm_ref_cell(curr); |
||
750 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
||
751 |
if (lbm_is_cons_rw(curr)) { |
||
752 |
lbm_value next = 0; |
||
753 |
value_assign(&next, cell->car); |
||
754 |
value_assign(&cell->car, prev); |
||
755 |
value_assign(&prev,curr); |
||
756 |
value_assign(&curr, next); |
||
757 |
} else if (lbm_type_of(curr) == LBM_TYPE_LISPARRAY) { |
||
758 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
||
759 |
lbm_value *arr_data = (lbm_value *)arr->data; |
||
760 |
size_t arr_size = (size_t)arr->size / sizeof(lbm_value); |
||
761 |
// C stack recursion as deep as there are nested arrays. |
||
762 |
// TODO: Try to do this without recursion on the C side. |
||
763 |
for (size_t i = 0; i < arr_size; i ++) { |
||
764 |
lbm_gc_mark_phase_nm(arr_data[i]); |
||
765 |
} |
||
766 |
} |
||
767 |
// Will jump out next iteration as gc mark is set in curr. |
||
768 |
} |
||
769 |
while (lbm_is_ptr(prev) && |
||
770 |
(lbm_dec_ptr(prev) != LBM_PTR_NULL) && |
||
771 |
lbm_get_gc_flag(lbm_car(prev)) ) { |
||
772 |
// clear the flag |
||
773 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
774 |
cell->car = lbm_clr_gc_flag(cell->car); |
||
775 |
lbm_value next = 0; |
||
776 |
value_assign(&next, cell->cdr); |
||
777 |
value_assign(&cell->cdr, curr); |
||
778 |
value_assign(&curr, prev); |
||
779 |
value_assign(&prev, next); |
||
780 |
} |
||
781 |
if (lbm_is_ptr(prev) && |
||
782 |
lbm_dec_ptr(prev) == LBM_PTR_NULL) { |
||
783 |
work_to_do = false; |
||
784 |
} else if (lbm_is_ptr(prev)) { |
||
785 |
// set the flag |
||
786 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
787 |
cell->car = lbm_set_gc_flag(cell->car); |
||
788 |
lbm_value next = 0; |
||
789 |
value_assign(&next, cell->car); |
||
790 |
value_assign(&cell->car, curr); |
||
791 |
value_assign(&curr, cell->cdr); |
||
792 |
value_assign(&cell->cdr, next); |
||
793 |
} |
||
794 |
} |
||
795 |
} |
||
796 |
|||
797 |
void lbm_gc_mark_phase(lbm_value root) { |
||
798 |
mutex_lock(&lbm_const_heap_mutex); |
||
799 |
lbm_gc_mark_phase_nm(root); |
||
800 |
mutex_unlock(&lbm_const_heap_mutex); |
||
801 |
} |
||
802 |
|||
803 |
#else |
||
804 |
/* ************************************************************ |
||
805 |
Explicit stack "recursive" mark phase |
||
806 |
|||
807 |
Trees are marked in a left subtree before rigth subtree, car first then cdr, |
||
808 |
way to favor lisp lists. This means that stack will grow slowly when |
||
809 |
marking right-leaning (cdr-recursive) data-structures while left-leaning |
||
810 |
(car-recursive) structures uses a lot of stack. |
||
811 |
|||
812 |
Lisp arrays contain an extra book-keeping field to keep track |
||
813 |
of how far into the array the marking process has gone. |
||
814 |
|||
815 |
TODO: DSW should be used as a last-resort if the GC stack is exhausted. |
||
816 |
If we use DSW as last-resort can we get away with a way smaller |
||
817 |
GC stack and unchanged performance (on sensible programs)? |
||
818 |
*/ |
||
819 |
|||
820 |
extern eval_context_t *ctx_running; |
||
821 |
10447418 |
void lbm_gc_mark_phase(lbm_value root) { |
|
822 |
lbm_value t_ptr; |
||
823 |
10447418 |
lbm_stack_t *s = &lbm_heap_state.gc_stack; |
|
824 |
10447418 |
s->data[s->sp++] = root; |
|
825 |
|||
826 |
✓✓ | 61125022 |
while (!lbm_stack_is_empty(s)) { |
827 |
lbm_value curr; |
||
828 |
50677604 |
lbm_pop(s, &curr); |
|
829 |
|||
830 |
113695386 |
mark_shortcut: |
|
831 |
|||
832 |
✓✓ | 113695386 |
if (!lbm_is_ptr(curr) || |
833 |
✗✓ | 69978662 |
(curr & LBM_PTR_TO_CONSTANT_BIT)) { |
834 |
48504006 |
continue; |
|
835 |
} |
||
836 |
|||
837 |
69978662 |
lbm_cons_t *cell = &lbm_heap_state.heap[lbm_dec_ptr(curr)]; |
|
838 |
|||
839 |
✓✓ | 69978662 |
if (lbm_get_gc_mark(cell->cdr)) { |
840 |
4766646 |
continue; |
|
841 |
} |
||
842 |
|||
843 |
65212016 |
t_ptr = lbm_type_of(curr); |
|
844 |
|||
845 |
// An array is marked in O(N) time using an additional 32bit |
||
846 |
// value per array that keeps track of how far into the array GC |
||
847 |
// has progressed. |
||
848 |
✓✓ | 65212016 |
if (t_ptr == LBM_TYPE_LISPARRAY) { |
849 |
21462 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
|
850 |
21462 |
lbm_value *arrdata = (lbm_value *)arr->data; |
|
851 |
21462 |
uint32_t index = arr->index; |
|
852 |
✓✗ | 21462 |
if (arr->size > 0) { |
853 |
21462 |
lbm_push(s, curr); // put array back as bookkeeping. |
|
854 |
// Potential optimization. |
||
855 |
// 1. CONS pointers are set to curr and recurse. |
||
856 |
// 2. Any other ptr is marked immediately and index is increased. |
||
857 |
✓✓✓✗ |
21462 |
if (lbm_is_ptr(arrdata[index]) && ((arrdata[index] & LBM_PTR_TO_CONSTANT_BIT) == 0) && |
858 |
✓✓ | 1834 |
!((arrdata[index] & LBM_CONTINUATION_INTERNAL) == LBM_CONTINUATION_INTERNAL)) { |
859 |
1680 |
lbm_cons_t *elt = &lbm_heap_state.heap[lbm_dec_ptr(arrdata[index])]; |
|
860 |
✓✓ | 1680 |
if (!lbm_get_gc_mark(elt->cdr)) { |
861 |
826 |
curr = arrdata[index]; |
|
862 |
826 |
goto mark_shortcut; |
|
863 |
} |
||
864 |
} |
||
865 |
✓✓ | 20636 |
if (index < ((arr->size/(sizeof(lbm_value))) - 1)) { |
866 |
18414 |
arr->index++; |
|
867 |
18414 |
continue; |
|
868 |
} |
||
869 |
2222 |
arr->index = 0; |
|
870 |
2222 |
lbm_pop(s, &curr); // Remove array from GC stack as we are done marking it. |
|
871 |
} |
||
872 |
2222 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
|
873 |
2222 |
lbm_heap_state.gc_marked ++; |
|
874 |
2222 |
continue; |
|
875 |
✓✓ | 65190554 |
} else if (t_ptr == LBM_TYPE_CHANNEL) { |
876 |
308330 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
|
877 |
308330 |
lbm_heap_state.gc_marked ++; |
|
878 |
// TODO: Can channels be explicitly freed ? |
||
879 |
✓✗ | 308330 |
if (cell->car != ENC_SYM_NIL) { |
880 |
308330 |
lbm_char_channel_t *chan = (lbm_char_channel_t *)cell->car; |
|
881 |
308330 |
curr = chan->dependency; |
|
882 |
308330 |
goto mark_shortcut; |
|
883 |
} |
||
884 |
continue; |
||
885 |
} |
||
886 |
|||
887 |
64882224 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
|
888 |
64882224 |
lbm_heap_state.gc_marked ++; |
|
889 |
|||
890 |
✓✓ | 64882224 |
if (t_ptr == LBM_TYPE_CONS) { |
891 |
✓✓ | 62708626 |
if (lbm_is_ptr(cell->cdr)) { |
892 |
✗✓ | 40210946 |
if (!lbm_push(s, cell->cdr)) { |
893 |
lbm_critical_error(); |
||
894 |
break; |
||
895 |
} |
||
896 |
} |
||
897 |
62708626 |
curr = cell->car; |
|
898 |
62708626 |
goto mark_shortcut; // Skip a push/pop |
|
899 |
} |
||
900 |
} |
||
901 |
10447418 |
} |
|
902 |
#endif |
||
903 |
|||
904 |
//Environments are proper lists with a 2 element list stored in each car. |
||
905 |
20293348 |
void lbm_gc_mark_env(lbm_value env) { |
|
906 |
20293348 |
lbm_value curr = env; |
|
907 |
lbm_cons_t *c; |
||
908 |
|||
909 |
✓✓ | 23765184 |
while (lbm_is_ptr(curr)) { |
910 |
3471836 |
c = lbm_ref_cell(curr); |
|
911 |
3471836 |
c->cdr = lbm_set_gc_mark(c->cdr); // mark the environent list structure. |
|
912 |
3471836 |
lbm_cons_t *b = lbm_ref_cell(c->car); |
|
913 |
3471836 |
b->cdr = lbm_set_gc_mark(b->cdr); // mark the binding list head cell. |
|
914 |
3471836 |
lbm_gc_mark_phase(b->cdr); // mark the bound object. |
|
915 |
3471836 |
lbm_heap_state.gc_marked +=2; |
|
916 |
3471836 |
curr = c->cdr; |
|
917 |
} |
||
918 |
20293348 |
} |
|
919 |
|||
920 |
|||
921 |
627684 |
void lbm_gc_mark_aux(lbm_uint *aux_data, lbm_uint aux_size) { |
|
922 |
✓✓ | 15036098 |
for (lbm_uint i = 0; i < aux_size; i ++) { |
923 |
✓✓ | 14408414 |
if (lbm_is_ptr(aux_data[i])) { |
924 |
8638398 |
lbm_type pt_t = lbm_type_of(aux_data[i]); |
|
925 |
8638398 |
lbm_uint pt_v = lbm_dec_ptr(aux_data[i]); |
|
926 |
✓✗✓✓ |
8638398 |
if( pt_t >= LBM_POINTER_TYPE_FIRST && |
927 |
4543304 |
pt_t <= LBM_POINTER_TYPE_LAST && |
|
928 |
✓✗ | 4543304 |
pt_v < lbm_heap_state.heap_size) { |
929 |
4543304 |
lbm_gc_mark_phase(aux_data[i]); |
|
930 |
} |
||
931 |
} |
||
932 |
} |
||
933 |
627684 |
} |
|
934 |
|||
935 |
1256568 |
void lbm_gc_mark_roots(lbm_uint *roots, lbm_uint num_roots) { |
|
936 |
✓✓ | 3144694 |
for (lbm_uint i = 0; i < num_roots; i ++) { |
937 |
1888126 |
lbm_gc_mark_phase(roots[i]); |
|
938 |
} |
||
939 |
1256568 |
} |
|
940 |
|||
941 |
// Sweep moves non-marked heap objects to the free list. |
||
942 |
614552 |
int lbm_gc_sweep_phase(void) { |
|
943 |
614552 |
unsigned int i = 0; |
|
944 |
614552 |
lbm_cons_t *heap = (lbm_cons_t *)lbm_heap_state.heap; |
|
945 |
|||
946 |
✓✓ | 1415099032 |
for (i = 0; i < lbm_heap_state.heap_size; i ++) { |
947 |
✓✓ | 1414484480 |
if ( lbm_get_gc_mark(heap[i].cdr)) { |
948 |
71939032 |
heap[i].cdr = lbm_clr_gc_mark(heap[i].cdr); |
|
949 |
} else { |
||
950 |
// Check if this cell is a pointer to an array |
||
951 |
// and free it. |
||
952 |
✓✓ | 1342545448 |
if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL) { |
953 |
✓✓✓✓ ✗✓✓ |
298972063 |
switch(heap[i].cdr) { |
954 |
|||
955 |
8397310 |
case ENC_SYM_IND_I_TYPE: /* fall through */ |
|
956 |
case ENC_SYM_IND_U_TYPE: |
||
957 |
case ENC_SYM_IND_F_TYPE: |
||
958 |
8397310 |
lbm_memory_free((lbm_uint*)heap[i].car); |
|
959 |
8397310 |
break; |
|
960 |
29008 |
case ENC_SYM_DEFRAG_LISPARRAY_TYPE: /* fall through */ |
|
961 |
case ENC_SYM_DEFRAG_ARRAY_TYPE: |
||
962 |
29008 |
lbm_defrag_mem_free((lbm_uint*)heap[i].car); |
|
963 |
29008 |
break; |
|
964 |
572580 |
case ENC_SYM_LISPARRAY_TYPE: /* fall through */ |
|
965 |
case ENC_SYM_ARRAY_TYPE:{ |
||
966 |
572580 |
lbm_array_header_t *arr = (lbm_array_header_t*)heap[i].car; |
|
967 |
572580 |
lbm_memory_free((lbm_uint *)arr->data); |
|
968 |
572580 |
lbm_heap_state.gc_recovered_arrays++; |
|
969 |
572580 |
lbm_memory_free((lbm_uint *)arr); |
|
970 |
572580 |
} break; |
|
971 |
304529 |
case ENC_SYM_CHANNEL_TYPE:{ |
|
972 |
304529 |
lbm_char_channel_t *chan = (lbm_char_channel_t*)heap[i].car; |
|
973 |
304529 |
lbm_memory_free((lbm_uint*)chan->state); |
|
974 |
304529 |
lbm_memory_free((lbm_uint*)chan); |
|
975 |
304529 |
} break; |
|
976 |
case ENC_SYM_CUSTOM_TYPE: { |
||
977 |
lbm_uint *t = (lbm_uint*)heap[i].car; |
||
978 |
lbm_custom_type_destroy(t); |
||
979 |
lbm_memory_free(t); |
||
980 |
} break; |
||
981 |
28 |
case ENC_SYM_DEFRAG_MEM_TYPE: { |
|
982 |
28 |
lbm_uint *ptr = (lbm_uint *)heap[i].car; |
|
983 |
28 |
lbm_defrag_mem_destroy(ptr); |
|
984 |
28 |
} break; |
|
985 |
289668608 |
default: |
|
986 |
289668608 |
break; |
|
987 |
} |
||
988 |
1043573385 |
} |
|
989 |
// create pointer to use as new freelist |
||
990 |
1342545448 |
lbm_uint addr = lbm_enc_cons_ptr(i); |
|
991 |
|||
992 |
// Clear the "freed" cell. |
||
993 |
1342545448 |
heap[i].car = ENC_SYM_RECOVERED; |
|
994 |
1342545448 |
heap[i].cdr = lbm_heap_state.freelist; |
|
995 |
1342545448 |
lbm_heap_state.freelist = addr; |
|
996 |
1342545448 |
lbm_heap_state.num_alloc --; |
|
997 |
1342545448 |
lbm_heap_state.gc_recovered ++; |
|
998 |
} |
||
999 |
} |
||
1000 |
614552 |
return 1; |
|
1001 |
} |
||
1002 |
|||
1003 |
614552 |
void lbm_gc_state_inc(void) { |
|
1004 |
614552 |
lbm_heap_state.gc_num ++; |
|
1005 |
614552 |
lbm_heap_state.gc_recovered = 0; |
|
1006 |
614552 |
lbm_heap_state.gc_marked = 0; |
|
1007 |
614552 |
} |
|
1008 |
|||
1009 |
// construct, alter and break apart |
||
1010 |
554383123 |
lbm_value lbm_cons(lbm_value car, lbm_value cdr) { |
|
1011 |
554383123 |
return lbm_heap_allocate_cell(LBM_TYPE_CONS, car, cdr); |
|
1012 |
} |
||
1013 |
|||
1014 |
572533149 |
lbm_value lbm_car(lbm_value c){ |
|
1015 |
✓✓ | 572533149 |
if (lbm_is_ptr(c) ){ |
1016 |
572532981 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1017 |
572532981 |
return cell->car; |
|
1018 |
} |
||
1019 |
✓✗ | 168 |
return c ? ENC_SYM_TERROR : c; //nil if c == nil |
1020 |
} |
||
1021 |
|||
1022 |
// TODO: Many comparisons "is this the nil symbol" can be |
||
1023 |
// streamlined a bit. NIL is 0 and cannot be confused with any other |
||
1024 |
// lbm_value. |
||
1025 |
|||
1026 |
46416 |
lbm_value lbm_caar(lbm_value c) { |
|
1027 |
46416 |
lbm_value tmp = ENC_SYM_NIL; |
|
1028 |
✓✗ | 46416 |
if (lbm_is_ptr(c)) { |
1029 |
46416 |
tmp = lbm_ref_cell(c)->car; |
|
1030 |
✓✗ | 46416 |
if (lbm_is_ptr(tmp)) { |
1031 |
46416 |
return lbm_ref_cell(tmp)->car; |
|
1032 |
} |
||
1033 |
} |
||
1034 |
return c || tmp ? ENC_SYM_TERROR : c; //nil if not something else |
||
1035 |
} |
||
1036 |
|||
1037 |
|||
1038 |
12348 |
lbm_value lbm_cadr(lbm_value c) { |
|
1039 |
12348 |
lbm_value tmp = ENC_SYM_NIL; |
|
1040 |
✓✗ | 12348 |
if (lbm_is_ptr(c)) { |
1041 |
12348 |
tmp = lbm_ref_cell(c)->cdr; |
|
1042 |
✓✗ | 12348 |
if (lbm_is_ptr(tmp)) { |
1043 |
12348 |
return lbm_ref_cell(tmp)->car; |
|
1044 |
} |
||
1045 |
} |
||
1046 |
return c || tmp ? ENC_SYM_TERROR : c; |
||
1047 |
} |
||
1048 |
|||
1049 |
136404586 |
lbm_value lbm_cdr(lbm_value c){ |
|
1050 |
✓✓ | 136404586 |
if (lbm_is_ptr(c)) { |
1051 |
135837978 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1052 |
135837978 |
return cell->cdr; |
|
1053 |
} |
||
1054 |
✓✗ | 566608 |
return c ? ENC_SYM_TERROR: c; |
1055 |
} |
||
1056 |
|||
1057 |
lbm_value lbm_cddr(lbm_value c) { |
||
1058 |
if (lbm_is_ptr(c)) { |
||
1059 |
lbm_value tmp = lbm_ref_cell(c)->cdr; |
||
1060 |
if (lbm_is_ptr(tmp)) { |
||
1061 |
return lbm_ref_cell(tmp)->cdr; |
||
1062 |
} |
||
1063 |
} |
||
1064 |
return c ? ENC_SYM_TERROR : c; |
||
1065 |
} |
||
1066 |
|||
1067 |
6859530 |
int lbm_set_car(lbm_value c, lbm_value v) { |
|
1068 |
6859530 |
int r = 0; |
|
1069 |
|||
1070 |
✓✓ | 6859530 |
if (lbm_type_of(c) == LBM_TYPE_CONS) { |
1071 |
6859502 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1072 |
6859502 |
cell->car = v; |
|
1073 |
6859502 |
r = 1; |
|
1074 |
} |
||
1075 |
6859530 |
return r; |
|
1076 |
} |
||
1077 |
|||
1078 |
124310586 |
int lbm_set_cdr(lbm_value c, lbm_value v) { |
|
1079 |
124310586 |
int r = 0; |
|
1080 |
✓✓ | 124310586 |
if (lbm_is_cons_rw(c)){ |
1081 |
123744062 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1082 |
123744062 |
cell->cdr = v; |
|
1083 |
123744062 |
r = 1; |
|
1084 |
} |
||
1085 |
124310586 |
return r; |
|
1086 |
} |
||
1087 |
|||
1088 |
29788326 |
int lbm_set_car_and_cdr(lbm_value c, lbm_value car_val, lbm_value cdr_val) { |
|
1089 |
29788326 |
int r = 0; |
|
1090 |
✓✗ | 29788326 |
if (lbm_is_cons_rw(c)) { |
1091 |
29788326 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1092 |
29788326 |
cell->car = car_val; |
|
1093 |
29788326 |
cell->cdr = cdr_val; |
|
1094 |
29788326 |
r = 1; |
|
1095 |
} |
||
1096 |
29788326 |
return r; |
|
1097 |
} |
||
1098 |
|||
1099 |
/* calculate length of a proper list */ |
||
1100 |
1248920 |
lbm_uint lbm_list_length(lbm_value c) { |
|
1101 |
1248920 |
lbm_uint len = 0; |
|
1102 |
|||
1103 |
✓✓ | 7213614 |
while (lbm_is_cons(c)){ |
1104 |
5964694 |
len ++; |
|
1105 |
5964694 |
c = lbm_cdr(c); |
|
1106 |
} |
||
1107 |
1248920 |
return len; |
|
1108 |
} |
||
1109 |
|||
1110 |
/* calculate the length of a list and check that each element |
||
1111 |
fullfills the predicate pred */ |
||
1112 |
unsigned int lbm_list_length_pred(lbm_value c, bool *pres, bool (*pred)(lbm_value)) { |
||
1113 |
bool res = true; |
||
1114 |
unsigned int len = 0; |
||
1115 |
|||
1116 |
while (lbm_is_cons(c)){ |
||
1117 |
len ++; |
||
1118 |
res = res && pred(lbm_car(c)); |
||
1119 |
c = lbm_cdr(c); |
||
1120 |
} |
||
1121 |
*pres = res; |
||
1122 |
return len; |
||
1123 |
} |
||
1124 |
|||
1125 |
/* reverse a proper list */ |
||
1126 |
lbm_value lbm_list_reverse(lbm_value list) { |
||
1127 |
if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
||
1128 |
return list; |
||
1129 |
} |
||
1130 |
|||
1131 |
lbm_value curr = list; |
||
1132 |
|||
1133 |
lbm_value new_list = ENC_SYM_NIL; |
||
1134 |
while (lbm_is_cons(curr)) { |
||
1135 |
|||
1136 |
new_list = lbm_cons(lbm_car(curr), new_list); |
||
1137 |
if (lbm_type_of(new_list) == LBM_TYPE_SYMBOL) { |
||
1138 |
return ENC_SYM_MERROR; |
||
1139 |
} |
||
1140 |
curr = lbm_cdr(curr); |
||
1141 |
} |
||
1142 |
return new_list; |
||
1143 |
} |
||
1144 |
|||
1145 |
10484 |
lbm_value lbm_list_destructive_reverse(lbm_value list) { |
|
1146 |
✗✓ | 10484 |
if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
1147 |
return list; |
||
1148 |
} |
||
1149 |
10484 |
lbm_value curr = list; |
|
1150 |
10484 |
lbm_value last_cell = ENC_SYM_NIL; |
|
1151 |
|||
1152 |
✓✓ | 37256 |
while (lbm_is_cons_rw(curr)) { |
1153 |
26772 |
lbm_value next = lbm_cdr(curr); |
|
1154 |
26772 |
lbm_set_cdr(curr, last_cell); |
|
1155 |
26772 |
last_cell = curr; |
|
1156 |
26772 |
curr = next; |
|
1157 |
} |
||
1158 |
10484 |
return last_cell; |
|
1159 |
} |
||
1160 |
|||
1161 |
|||
1162 |
330382 |
lbm_value lbm_list_copy(int *m, lbm_value list) { |
|
1163 |
330382 |
lbm_value curr = list; |
|
1164 |
330382 |
lbm_uint n = lbm_list_length(list); |
|
1165 |
330382 |
lbm_uint copy_n = n; |
|
1166 |
✓✓✓✓ |
330382 |
if (*m >= 0 && (lbm_uint)*m < n) { |
1167 |
5414 |
copy_n = (lbm_uint)*m; |
|
1168 |
✓✓ | 324968 |
} else if (*m == -1) { |
1169 |
295666 |
*m = (int)n; // TODO: smaller range in target variable. |
|
1170 |
} |
||
1171 |
✓✓ | 330382 |
if (copy_n == 0) return ENC_SYM_NIL; |
1172 |
330158 |
lbm_uint new_list = lbm_heap_allocate_list(copy_n); |
|
1173 |
✓✓ | 330158 |
if (lbm_is_symbol(new_list)) return new_list; |
1174 |
329410 |
lbm_value curr_targ = new_list; |
|
1175 |
|||
1176 |
✓✓✓✓ |
4090636 |
while (lbm_is_cons(curr) && copy_n > 0) { |
1177 |
3761226 |
lbm_value v = lbm_car(curr); |
|
1178 |
3761226 |
lbm_set_car(curr_targ, v); |
|
1179 |
3761226 |
curr_targ = lbm_cdr(curr_targ); |
|
1180 |
3761226 |
curr = lbm_cdr(curr); |
|
1181 |
3761226 |
copy_n --; |
|
1182 |
} |
||
1183 |
|||
1184 |
329410 |
return new_list; |
|
1185 |
} |
||
1186 |
|||
1187 |
// Append for proper lists only |
||
1188 |
// Destructive update of list1. |
||
1189 |
23992 |
lbm_value lbm_list_append(lbm_value list1, lbm_value list2) { |
|
1190 |
|||
1191 |
✓✗✓✗ |
47984 |
if(lbm_is_list_rw(list1) && |
1192 |
23992 |
lbm_is_list(list2)) { |
|
1193 |
|||
1194 |
23992 |
lbm_value curr = list1; |
|
1195 |
✓✓ | 55902 |
while(lbm_type_of(lbm_cdr(curr)) == LBM_TYPE_CONS) { |
1196 |
31910 |
curr = lbm_cdr(curr); |
|
1197 |
} |
||
1198 |
✓✓ | 23992 |
if (lbm_is_symbol_nil(curr)) return list2; |
1199 |
23964 |
lbm_set_cdr(curr, list2); |
|
1200 |
23964 |
return list1; |
|
1201 |
} |
||
1202 |
return ENC_SYM_EERROR; |
||
1203 |
} |
||
1204 |
|||
1205 |
84 |
lbm_value lbm_list_drop(unsigned int n, lbm_value ls) { |
|
1206 |
84 |
lbm_value curr = ls; |
|
1207 |
✓✓✓✓ |
784 |
while (lbm_type_of_functional(curr) == LBM_TYPE_CONS && |
1208 |
n > 0) { |
||
1209 |
700 |
curr = lbm_cdr(curr); |
|
1210 |
700 |
n --; |
|
1211 |
} |
||
1212 |
84 |
return curr; |
|
1213 |
} |
||
1214 |
|||
1215 |
153072 |
lbm_value lbm_index_list(lbm_value l, int32_t n) { |
|
1216 |
153072 |
lbm_value curr = l; |
|
1217 |
|||
1218 |
✓✓ | 153072 |
if (n < 0) { |
1219 |
112 |
int32_t len = (int32_t)lbm_list_length(l); |
|
1220 |
112 |
n = len + n; |
|
1221 |
✗✓ | 112 |
if (n < 0) return ENC_SYM_NIL; |
1222 |
} |
||
1223 |
|||
1224 |
✓✓✓✓ |
229510 |
while (lbm_is_cons(curr) && |
1225 |
n > 0) { |
||
1226 |
76438 |
curr = lbm_cdr(curr); |
|
1227 |
76438 |
n --; |
|
1228 |
} |
||
1229 |
✓✓ | 153072 |
if (lbm_is_cons(curr)) { |
1230 |
153044 |
return lbm_car(curr); |
|
1231 |
} else { |
||
1232 |
28 |
return ENC_SYM_NIL; |
|
1233 |
} |
||
1234 |
} |
||
1235 |
|||
1236 |
// High-level arrays are just bytearrays but with a different tag and pointer type. |
||
1237 |
// These arrays will be inspected by GC and the elements of the array will be marked. |
||
1238 |
|||
1239 |
// Arrays are part of the heap module because their lifespan is managed |
||
1240 |
// by the garbage collector. The data in the array is not stored |
||
1241 |
// in the "heap of cons cells". |
||
1242 |
575752 |
int lbm_heap_allocate_array_base(lbm_value *res, bool byte_array, lbm_uint size){ |
|
1243 |
|||
1244 |
575752 |
lbm_uint tag = ENC_SYM_ARRAY_TYPE; |
|
1245 |
575752 |
lbm_uint type = LBM_TYPE_ARRAY; |
|
1246 |
575752 |
lbm_array_header_t *array = NULL; |
|
1247 |
575752 |
lbm_array_header_extended_t *ext_array = NULL; |
|
1248 |
|||
1249 |
✓✓ | 575752 |
if (byte_array) { |
1250 |
293208 |
array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t)); |
|
1251 |
} else { |
||
1252 |
282544 |
tag = ENC_SYM_LISPARRAY_TYPE; |
|
1253 |
282544 |
type = LBM_TYPE_LISPARRAY; |
|
1254 |
282544 |
size = sizeof(lbm_value) * size; |
|
1255 |
282544 |
array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_extended_t)); |
|
1256 |
282544 |
ext_array = (lbm_array_header_extended_t*)array; |
|
1257 |
} |
||
1258 |
✓✓ | 575752 |
if (array) { |
1259 |
✓✓ | 574834 |
if (!byte_array) ext_array->index = 0; |
1260 |
|||
1261 |
574834 |
array->data = NULL; |
|
1262 |
574834 |
array->size = size; |
|
1263 |
✓✓ | 574834 |
if ( size > 0) { |
1264 |
574694 |
array->data = (lbm_uint*)lbm_malloc(size); |
|
1265 |
✓✓ | 574694 |
if (array->data == NULL) { |
1266 |
5758 |
lbm_memory_free((lbm_uint*)array); |
|
1267 |
5758 |
goto allocate_array_merror; |
|
1268 |
} |
||
1269 |
// It is more important to zero out high-level arrays. |
||
1270 |
// 0 is symbol NIL which is perfectly safe for the GC to inspect. |
||
1271 |
568936 |
memset(array->data, 0, size); |
|
1272 |
} |
||
1273 |
// allocating a cell for array's heap-presence |
||
1274 |
569076 |
lbm_value cell = lbm_heap_allocate_cell(type, (lbm_uint) array, tag); |
|
1275 |
✓✓ | 569076 |
if (cell == ENC_SYM_MERROR) { |
1276 |
302 |
lbm_memory_free((lbm_uint*)array->data); |
|
1277 |
302 |
lbm_memory_free((lbm_uint*)array); |
|
1278 |
302 |
goto allocate_array_merror; |
|
1279 |
} |
||
1280 |
568774 |
*res = cell; |
|
1281 |
568774 |
lbm_heap_state.num_alloc_arrays ++; |
|
1282 |
568774 |
return 1; |
|
1283 |
} |
||
1284 |
918 |
allocate_array_merror: |
|
1285 |
6978 |
*res = ENC_SYM_MERROR; |
|
1286 |
6978 |
return 0; |
|
1287 |
} |
||
1288 |
|||
1289 |
293208 |
int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){ |
|
1290 |
293208 |
return lbm_heap_allocate_array_base(res, true, size); |
|
1291 |
} |
||
1292 |
|||
1293 |
282544 |
int lbm_heap_allocate_lisp_array(lbm_value *res, lbm_uint size) { |
|
1294 |
282544 |
return lbm_heap_allocate_array_base(res, false, size); |
|
1295 |
} |
||
1296 |
|||
1297 |
int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) { |
||
1298 |
|||
1299 |
lbm_array_header_t *array = NULL; |
||
1300 |
lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE); |
||
1301 |
|||
1302 |
if (cell == ENC_SYM_MERROR) { |
||
1303 |
*value = cell; |
||
1304 |
return 0; |
||
1305 |
} |
||
1306 |
|||
1307 |
array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t)); |
||
1308 |
|||
1309 |
if (array == NULL) { |
||
1310 |
lbm_set_car_and_cdr(cell, ENC_SYM_NIL, ENC_SYM_NIL); |
||
1311 |
*value = ENC_SYM_MERROR; |
||
1312 |
return 0; |
||
1313 |
} |
||
1314 |
|||
1315 |
array->data = (lbm_uint*)data; |
||
1316 |
array->size = num_elt; |
||
1317 |
|||
1318 |
lbm_set_car(cell, (lbm_uint)array); |
||
1319 |
|||
1320 |
cell = lbm_set_ptr_type(cell, LBM_TYPE_ARRAY); |
||
1321 |
*value = cell; |
||
1322 |
return 1; |
||
1323 |
} |
||
1324 |
|||
1325 |
237416 |
lbm_int lbm_heap_array_get_size(lbm_value arr) { |
|
1326 |
|||
1327 |
237416 |
lbm_int r = -1; |
|
1328 |
237416 |
lbm_array_header_t *header = lbm_dec_array_r(arr); |
|
1329 |
✓✗ | 237416 |
if (header) { |
1330 |
237416 |
r = (lbm_int)header->size; |
|
1331 |
} |
||
1332 |
237416 |
return r; |
|
1333 |
} |
||
1334 |
|||
1335 |
118692 |
const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) { |
|
1336 |
118692 |
uint8_t *r = NULL; |
|
1337 |
118692 |
lbm_array_header_t *header = lbm_dec_array_r(arr); |
|
1338 |
✓✗ | 118692 |
if (header) { |
1339 |
118692 |
r = (uint8_t*)header->data; |
|
1340 |
} |
||
1341 |
118692 |
return r; |
|
1342 |
} |
||
1343 |
|||
1344 |
uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) { |
||
1345 |
uint8_t *r = NULL; |
||
1346 |
lbm_array_header_t *header = lbm_dec_array_rw(arr); |
||
1347 |
if (header) { |
||
1348 |
r = (uint8_t*)header->data; |
||
1349 |
} |
||
1350 |
return r; |
||
1351 |
} |
||
1352 |
|||
1353 |
|||
1354 |
/* Explicitly freeing an array. |
||
1355 |
|||
1356 |
This is a highly unsafe operation and can only be safely |
||
1357 |
used if the heap cell that points to the array has not been made |
||
1358 |
accessible to the program. |
||
1359 |
|||
1360 |
So This function can be used to free an array in case an array |
||
1361 |
is being constructed and some error case appears while doing so |
||
1362 |
If the array still have not become available it can safely be |
||
1363 |
"explicitly" freed. |
||
1364 |
|||
1365 |
The problem is that if the "array" heap-cell is made available to |
||
1366 |
the program, this cell can easily be duplicated and we would have |
||
1367 |
to search the entire heap to find all cells pointing to the array |
||
1368 |
memory in question and "null"-them out before freeing the memory |
||
1369 |
*/ |
||
1370 |
|||
1371 |
112 |
int lbm_heap_explicit_free_array(lbm_value arr) { |
|
1372 |
|||
1373 |
112 |
int r = 0; |
|
1374 |
✓✗✓✗ |
112 |
if (lbm_is_array_rw(arr) && lbm_cdr(arr) == ENC_SYM_ARRAY_TYPE) { |
1375 |
112 |
lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr); |
|
1376 |
✗✓ | 112 |
if (header == NULL) { |
1377 |
return 0; |
||
1378 |
} |
||
1379 |
112 |
lbm_memory_free((lbm_uint*)header->data); |
|
1380 |
112 |
lbm_memory_free((lbm_uint*)header); |
|
1381 |
|||
1382 |
112 |
arr = lbm_set_ptr_type(arr, LBM_TYPE_CONS); |
|
1383 |
112 |
lbm_set_car(arr, ENC_SYM_NIL); |
|
1384 |
112 |
lbm_set_cdr(arr, ENC_SYM_NIL); |
|
1385 |
112 |
r = 1; |
|
1386 |
} |
||
1387 |
|||
1388 |
112 |
return r; |
|
1389 |
} |
||
1390 |
|||
1391 |
lbm_uint lbm_size_of(lbm_type t) { |
||
1392 |
lbm_uint s = 0; |
||
1393 |
switch(t) { |
||
1394 |
case LBM_TYPE_BYTE: |
||
1395 |
s = 1; |
||
1396 |
break; |
||
1397 |
case LBM_TYPE_I: /* fall through */ |
||
1398 |
case LBM_TYPE_U: |
||
1399 |
case LBM_TYPE_SYMBOL: |
||
1400 |
s = sizeof(lbm_uint); |
||
1401 |
break; |
||
1402 |
case LBM_TYPE_I32: /* fall through */ |
||
1403 |
case LBM_TYPE_U32: |
||
1404 |
case LBM_TYPE_FLOAT: |
||
1405 |
s = 4; |
||
1406 |
break; |
||
1407 |
case LBM_TYPE_I64: /* fall through */ |
||
1408 |
case LBM_TYPE_U64: |
||
1409 |
case LBM_TYPE_DOUBLE: |
||
1410 |
s = 8; |
||
1411 |
break; |
||
1412 |
} |
||
1413 |
return s; |
||
1414 |
} |
||
1415 |
|||
1416 |
static bool dummy_flash_write(lbm_uint ix, lbm_uint val) { |
||
1417 |
(void)ix; |
||
1418 |
(void)val; |
||
1419 |
return false; |
||
1420 |
} |
||
1421 |
|||
1422 |
static const_heap_write_fun const_heap_write = dummy_flash_write; |
||
1423 |
|||
1424 |
21924 |
int lbm_const_heap_init(const_heap_write_fun w_fun, |
|
1425 |
lbm_const_heap_t *heap, |
||
1426 |
lbm_uint *addr) { |
||
1427 |
✗✓ | 21924 |
if (((uintptr_t)addr % 4) != 0) return 0; |
1428 |
|||
1429 |
✓✗ | 21924 |
if (!lbm_const_heap_mutex_initialized) { |
1430 |
21924 |
mutex_init(&lbm_const_heap_mutex); |
|
1431 |
21924 |
lbm_const_heap_mutex_initialized = true; |
|
1432 |
} |
||
1433 |
|||
1434 |
✓✗ | 21924 |
if (!lbm_mark_mutex_initialized) { |
1435 |
21924 |
mutex_init(&lbm_mark_mutex); |
|
1436 |
21924 |
lbm_mark_mutex_initialized = true; |
|
1437 |
} |
||
1438 |
|||
1439 |
21924 |
const_heap_write = w_fun; |
|
1440 |
|||
1441 |
21924 |
heap->heap = addr; |
|
1442 |
21924 |
heap->size = 0; |
|
1443 |
21924 |
heap->next = 0; |
|
1444 |
|||
1445 |
21924 |
lbm_const_heap_state = heap; |
|
1446 |
// ref_cell views the lbm_uint array as an lbm_cons_t array |
||
1447 |
21924 |
lbm_heaps[1] = (lbm_cons_t*)addr; |
|
1448 |
21924 |
return 1; |
|
1449 |
} |
||
1450 |
|||
1451 |
2352 |
lbm_flash_status lbm_allocate_const_cell(lbm_value *res) { |
|
1452 |
2352 |
lbm_flash_status r = LBM_FLASH_FULL; |
|
1453 |
|||
1454 |
2352 |
mutex_lock(&lbm_const_heap_mutex); |
|
1455 |
// waste a cell if we have ended up unaligned after writing an array to flash. |
||
1456 |
✓✓ | 2352 |
if (lbm_const_heap_state->next % 2 == 1) { |
1457 |
126 |
lbm_const_heap_state->next++; |
|
1458 |
} |
||
1459 |
|||
1460 |
✓✗ | 2352 |
if (lbm_const_heap_state && |
1461 |
✓✗ | 2352 |
(lbm_const_heap_state->next+1) < (uint32_t)lbm_image_get_write_index()) { |
1462 |
// A cons cell uses two words. |
||
1463 |
2352 |
lbm_value cell = lbm_const_heap_state->next; |
|
1464 |
2352 |
lbm_const_heap_state->next += 2; |
|
1465 |
2352 |
*res = (cell << LBM_ADDRESS_SHIFT) | LBM_PTR_BIT | LBM_TYPE_CONS | LBM_PTR_TO_CONSTANT_BIT; |
|
1466 |
2352 |
r = LBM_FLASH_WRITE_OK; |
|
1467 |
} |
||
1468 |
2352 |
mutex_unlock(&lbm_const_heap_mutex); |
|
1469 |
2352 |
return r; |
|
1470 |
} |
||
1471 |
|||
1472 |
28 |
lbm_flash_status lbm_allocate_const_raw(lbm_uint nwords, lbm_uint *res) { |
|
1473 |
28 |
lbm_flash_status r = LBM_FLASH_FULL; |
|
1474 |
|||
1475 |
✓✗ | 28 |
if (lbm_const_heap_state && |
1476 |
✓✗ | 28 |
(lbm_const_heap_state->next + nwords) < (uint32_t)lbm_image_get_write_index()) { |
1477 |
28 |
lbm_uint ix = lbm_const_heap_state->next; |
|
1478 |
28 |
*res = (lbm_uint)&lbm_const_heap_state->heap[ix]; |
|
1479 |
28 |
lbm_const_heap_state->next += nwords; |
|
1480 |
28 |
r = LBM_FLASH_WRITE_OK; |
|
1481 |
} |
||
1482 |
28 |
return r; |
|
1483 |
} |
||
1484 |
|||
1485 |
186352 |
lbm_flash_status lbm_write_const_raw(lbm_uint *data, lbm_uint n, lbm_uint *res) { |
|
1486 |
|||
1487 |
186352 |
lbm_flash_status r = LBM_FLASH_FULL; |
|
1488 |
|||
1489 |
✓✗ | 186352 |
if (lbm_const_heap_state && |
1490 |
✓✗ | 186352 |
(lbm_const_heap_state->next + n) < (uint32_t)lbm_image_get_write_index()) { |
1491 |
186352 |
lbm_uint ix = lbm_const_heap_state->next; |
|
1492 |
|||
1493 |
✓✓ | 389728 |
for (unsigned int i = 0; i < n; i ++) { |
1494 |
✗✓ | 203376 |
if (!const_heap_write(((lbm_uint*)data)[i],ix + i)) |
1495 |
return LBM_FLASH_WRITE_ERROR; |
||
1496 |
} |
||
1497 |
186352 |
lbm_const_heap_state->next += n; |
|
1498 |
186352 |
*res = (lbm_uint)&lbm_const_heap_state->heap[ix]; |
|
1499 |
186352 |
r = LBM_FLASH_WRITE_OK; |
|
1500 |
} |
||
1501 |
186352 |
return r; |
|
1502 |
} |
||
1503 |
|||
1504 |
84 |
lbm_flash_status lbm_const_write(lbm_uint *tgt, lbm_uint val) { |
|
1505 |
|||
1506 |
✓✗ | 84 |
if (lbm_const_heap_state) { |
1507 |
84 |
lbm_uint flash = (lbm_uint)lbm_const_heap_state->heap; |
|
1508 |
84 |
lbm_uint ix = (((lbm_uint)tgt - flash) / sizeof(lbm_uint)); // byte address to ix |
|
1509 |
✓✗ | 84 |
if (const_heap_write(val, ix)) { |
1510 |
84 |
return LBM_FLASH_WRITE_OK; |
|
1511 |
} |
||
1512 |
return LBM_FLASH_WRITE_ERROR; |
||
1513 |
} |
||
1514 |
return LBM_FLASH_FULL; |
||
1515 |
} |
||
1516 |
|||
1517 |
2352 |
lbm_flash_status write_const_cdr(lbm_value cell, lbm_value val) { |
|
1518 |
2352 |
lbm_uint addr = lbm_dec_ptr(cell); |
|
1519 |
✓✗ | 2352 |
if (const_heap_write(val, addr+1)) |
1520 |
2352 |
return LBM_FLASH_WRITE_OK; |
|
1521 |
return LBM_FLASH_WRITE_ERROR; |
||
1522 |
} |
||
1523 |
|||
1524 |
2352 |
lbm_flash_status write_const_car(lbm_value cell, lbm_value val) { |
|
1525 |
2352 |
lbm_uint addr = lbm_dec_ptr(cell); |
|
1526 |
✓✗ | 2352 |
if (const_heap_write(val, addr)) |
1527 |
2352 |
return LBM_FLASH_WRITE_OK; |
|
1528 |
return LBM_FLASH_WRITE_ERROR; |
||
1529 |
} |
||
1530 |
|||
1531 |
lbm_uint lbm_flash_memory_usage(void) { |
||
1532 |
return lbm_const_heap_state->next; |
||
1533 |
} |
||
1534 |
|||
1535 |
|||
1536 |
// //////////////////////////////////////////////////////////// |
||
1537 |
// pointer reversal traversal |
||
1538 |
// |
||
1539 |
// Caveats: |
||
1540 |
// * Structures on the constant heap cannot be traversed using |
||
1541 |
// pointer reversal. If a dynamic structure is pointing into the |
||
1542 |
// constant heap, the 'f' will be applied to the constant cons cell on |
||
1543 |
// the border and then traversal will retreat. |
||
1544 |
// * Traversal is for trees and graphs without cycles. |
||
1545 |
// - Note that if used to "flatten" a graph, the resulting flat |
||
1546 |
// value will encode a tree where sharing is duplicated. |
||
1547 |
// - NOT suitable for flattening in general, but should be |
||
1548 |
// a perfect fit for the flattening we do into images. |
||
1549 |
|||
1550 |
bool lbm_ptr_rev_trav(void (*f)(lbm_value, void*), lbm_value v, void* arg) { |
||
1551 |
|||
1552 |
bool cyclic = false; |
||
1553 |
lbm_value curr = v; |
||
1554 |
lbm_value prev = lbm_enc_cons_ptr(LBM_PTR_NULL); |
||
1555 |
|||
1556 |
while (true) { |
||
1557 |
|||
1558 |
// Run leftwards and process conses until |
||
1559 |
// hitting a leaf in the left direction. |
||
1560 |
while ((lbm_is_cons_rw(curr) && |
||
1561 |
!gc_marked(curr)) || // do not step into a loop |
||
1562 |
lbm_is_lisp_array_rw(curr)) { // do not step into the constant heap |
||
1563 |
lbm_cons_t *cell = lbm_ref_cell(curr); |
||
1564 |
if (lbm_is_cons(curr)) { |
||
1565 |
gc_mark(curr); |
||
1566 |
// In-order traversal |
||
1567 |
f(curr, arg); |
||
1568 |
lbm_value next = 0; |
||
1569 |
value_assign(&next, cell->car); |
||
1570 |
value_assign(&cell->car, prev); |
||
1571 |
value_assign(&prev, curr); |
||
1572 |
value_assign(&curr, next); |
||
1573 |
} else { // it is an array |
||
1574 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
||
1575 |
lbm_value *arr_data = (lbm_value *)arr->data; |
||
1576 |
uint32_t index = arr->index; |
||
1577 |
if (arr->size == 0) break; |
||
1578 |
if (index == 0) { // index should only be 0 or there is a potential cycle |
||
1579 |
f(curr, arg); |
||
1580 |
arr->index = 1; |
||
1581 |
|||
1582 |
lbm_value next = 0; |
||
1583 |
value_assign(&next, arr_data[0]); |
||
1584 |
value_assign(&arr_data[0], prev); |
||
1585 |
value_assign(&prev, curr); |
||
1586 |
value_assign(&curr, next); |
||
1587 |
} else { |
||
1588 |
cyclic = true; |
||
1589 |
break; |
||
1590 |
} |
||
1591 |
} |
||
1592 |
} |
||
1593 |
|||
1594 |
if (!lbm_is_cons(curr) || // Found a leaf |
||
1595 |
(curr & LBM_PTR_TO_CONSTANT_BIT)) { |
||
1596 |
f(curr, arg); |
||
1597 |
} else if (gc_marked(curr)) { |
||
1598 |
cyclic = true; |
||
1599 |
gc_clear_mark(curr); |
||
1600 |
} |
||
1601 |
|||
1602 |
// Now either prev has the "flag" set or it doesnt. |
||
1603 |
// If the flag is set that means that the prev node |
||
1604 |
// have had both its car and cdr visited. So that node is done! |
||
1605 |
// |
||
1606 |
// If the flag is not set, jump down to SWAP |
||
1607 |
|||
1608 |
while ((lbm_is_cons(prev) && |
||
1609 |
(lbm_dec_ptr(prev) != LBM_PTR_NULL) && // is LBM_NULL a cons type? |
||
1610 |
lbm_get_gc_flag(lbm_car(prev))) || |
||
1611 |
lbm_is_lisp_array_rw(prev)) { |
||
1612 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
1613 |
if (lbm_is_cons(prev)) { |
||
1614 |
|||
1615 |
// clear the flag |
||
1616 |
// This means that we are done with a "CDR" child. |
||
1617 |
// prev = [ a , b ][flag = 1] |
||
1618 |
// => |
||
1619 |
// prev = [ a , b ][flag = 0] |
||
1620 |
|||
1621 |
gc_clear_mark(prev); |
||
1622 |
cell->car = lbm_clr_gc_flag(cell->car); |
||
1623 |
// Move on downwards until |
||
1624 |
// finding a cons cell without flag or NULL |
||
1625 |
|||
1626 |
// curr = c |
||
1627 |
// prev = [ a , b ][flag = 0] |
||
1628 |
// => |
||
1629 |
// prev = [ a , c ][flag = 0] |
||
1630 |
// curr = prev |
||
1631 |
// prev = b |
||
1632 |
|||
1633 |
lbm_value next = 0; |
||
1634 |
value_assign(&next, cell->cdr); |
||
1635 |
value_assign(&cell->cdr, curr); |
||
1636 |
value_assign(&curr, prev); |
||
1637 |
value_assign(&prev, next); |
||
1638 |
} else { // is an array |
||
1639 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
||
1640 |
lbm_value *arr_data = (lbm_value *)arr->data; |
||
1641 |
size_t arr_size = (size_t)arr->size / sizeof(lbm_value); |
||
1642 |
lbm_value next = 0; |
||
1643 |
if (arr->index == arr_size) { |
||
1644 |
value_assign(&next, arr_data[arr->index-1]); |
||
1645 |
value_assign(&arr_data[arr->index-1], curr); |
||
1646 |
value_assign(&curr, prev); |
||
1647 |
value_assign(&prev, next); |
||
1648 |
arr->index = 0; |
||
1649 |
} else { |
||
1650 |
break; |
||
1651 |
} |
||
1652 |
} |
||
1653 |
} |
||
1654 |
|||
1655 |
// SWAP |
||
1656 |
|||
1657 |
// if the prev node is NULL we have traced backwards all the |
||
1658 |
// way back to where curr == v. Another alternative is that |
||
1659 |
// the input v was an Atom. We are done! |
||
1660 |
if (lbm_is_ptr(prev) && |
||
1661 |
lbm_dec_ptr(prev) == LBM_PTR_NULL) { |
||
1662 |
if (lbm_is_cons(curr)) { |
||
1663 |
gc_clear_mark(curr); |
||
1664 |
} |
||
1665 |
//done = true; |
||
1666 |
break; |
||
1667 |
} |
||
1668 |
|||
1669 |
// if the prev node is not NULL then we should move |
||
1670 |
// down to the prev node and start process its remaining child. |
||
1671 |
else if (lbm_is_cons(prev)) { |
||
1672 |
|||
1673 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
1674 |
lbm_value next = 0; |
||
1675 |
|||
1676 |
|||
1677 |
// prev = [ p , cdr ][flag = 0] |
||
1678 |
// => |
||
1679 |
// prev = [ p , cdr ][flag = 1] |
||
1680 |
|||
1681 |
cell->car = lbm_set_gc_flag(cell->car); |
||
1682 |
|||
1683 |
// switch to processing the cdr field and set the flag. |
||
1684 |
// curr = c |
||
1685 |
// prev = [ a, b ][flag = 1] |
||
1686 |
// => |
||
1687 |
// prev = [ c, a ][flag = 1] |
||
1688 |
// curr = b |
||
1689 |
|||
1690 |
value_assign(&next, cell->car); |
||
1691 |
value_assign(&cell->car, curr); |
||
1692 |
value_assign(&curr, cell->cdr); |
||
1693 |
value_assign(&cell->cdr, next); |
||
1694 |
} else if (lbm_is_lisp_array_rw(prev)) { |
||
1695 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
1696 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
||
1697 |
lbm_value *arr_data = (lbm_value *)arr->data; |
||
1698 |
lbm_value next = 0; |
||
1699 |
|||
1700 |
value_assign(&next, arr_data[arr->index-1]); |
||
1701 |
value_assign(&arr_data[arr->index-1], curr); |
||
1702 |
value_assign(&curr, arr_data[arr->index]); |
||
1703 |
value_assign(&arr_data[arr->index], next); |
||
1704 |
arr->index = arr->index + 1; |
||
1705 |
} |
||
1706 |
} |
||
1707 |
return !cyclic; |
||
1708 |
} |
Generated by: GCOVR (Version 4.2) |