GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
Copyright 2018, 2020, 2022 - 2024 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 |
|||
28 |
#include "heap.h" |
||
29 |
#include "symrepr.h" |
||
30 |
#include "stack.h" |
||
31 |
#include "lbm_channel.h" |
||
32 |
#include "platform_mutex.h" |
||
33 |
#include "eval_cps.h" |
||
34 |
#ifdef VISUALIZE_HEAP |
||
35 |
#include "heap_vis.h" |
||
36 |
#endif |
||
37 |
|||
38 |
|||
39 |
33797927 |
static inline lbm_value lbm_set_gc_mark(lbm_value x) { |
|
40 |
33797927 |
return x | LBM_GC_MARKED; |
|
41 |
} |
||
42 |
|||
43 |
33631697 |
static inline lbm_value lbm_clr_gc_mark(lbm_value x) { |
|
44 |
33631697 |
return x & ~LBM_GC_MASK; |
|
45 |
} |
||
46 |
|||
47 |
804518484 |
static inline bool lbm_get_gc_mark(lbm_value x) { |
|
48 |
804518484 |
return x & LBM_GC_MASK; |
|
49 |
} |
||
50 |
|||
51 |
// flag is the same bit as mark, but in car |
||
52 |
static inline bool lbm_get_gc_flag(lbm_value x) { |
||
53 |
return x & LBM_GC_MARKED; |
||
54 |
} |
||
55 |
|||
56 |
static inline lbm_value lbm_set_gc_flag(lbm_value x) { |
||
57 |
return x | LBM_GC_MARKED; |
||
58 |
} |
||
59 |
|||
60 |
static inline lbm_value lbm_clr_gc_flag(lbm_value x) { |
||
61 |
return x & ~LBM_GC_MASK; |
||
62 |
} |
||
63 |
|||
64 |
|||
65 |
lbm_heap_state_t lbm_heap_state; |
||
66 |
|||
67 |
lbm_const_heap_t *lbm_const_heap_state; |
||
68 |
|||
69 |
lbm_cons_t *lbm_heaps[2] = {NULL, NULL}; |
||
70 |
|||
71 |
static mutex_t lbm_const_heap_mutex; |
||
72 |
static bool lbm_const_heap_mutex_initialized = false; |
||
73 |
|||
74 |
static mutex_t lbm_mark_mutex; |
||
75 |
static bool lbm_mark_mutex_initialized = false; |
||
76 |
|||
77 |
#ifdef USE_GC_PTR_REV |
||
78 |
void lbm_gc_lock(void) { |
||
79 |
mutex_lock(&lbm_mark_mutex); |
||
80 |
} |
||
81 |
void lbm_gc_unlock(void) { |
||
82 |
mutex_unlock(&lbm_mark_mutex); |
||
83 |
} |
||
84 |
#else |
||
85 |
void lbm_gc_lock(void) { |
||
86 |
} |
||
87 |
void lbm_gc_unlock(void) { |
||
88 |
} |
||
89 |
#endif |
||
90 |
|||
91 |
/****************************************************/ |
||
92 |
/* ENCODERS DECODERS */ |
||
93 |
|||
94 |
2849162 |
lbm_value lbm_enc_i32(int32_t x) { |
|
95 |
#ifndef LBM64 |
||
96 |
2849162 |
lbm_value i = lbm_cons((lbm_uint)x, ENC_SYM_RAW_I_TYPE); |
|
97 |
✓✓ | 2849162 |
if (lbm_type_of(i) == LBM_TYPE_SYMBOL) return i; |
98 |
2839488 |
return lbm_set_ptr_type(i, LBM_TYPE_I32); |
|
99 |
#else |
||
100 |
return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_I32; |
||
101 |
#endif |
||
102 |
} |
||
103 |
|||
104 |
3682448 |
lbm_value lbm_enc_u32(uint32_t x) { |
|
105 |
#ifndef LBM64 |
||
106 |
3682448 |
lbm_value u = lbm_cons(x, ENC_SYM_RAW_U_TYPE); |
|
107 |
✓✓ | 3682448 |
if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
108 |
3679620 |
return lbm_set_ptr_type(u, LBM_TYPE_U32); |
|
109 |
#else |
||
110 |
return (((lbm_uint)x) << LBM_VAL_SHIFT) | LBM_TYPE_U32; |
||
111 |
#endif |
||
112 |
} |
||
113 |
|||
114 |
19877 |
lbm_value lbm_enc_float(float x) { |
|
115 |
#ifndef LBM64 |
||
116 |
lbm_uint t; |
||
117 |
19877 |
memcpy(&t, &x, sizeof(lbm_float)); |
|
118 |
19877 |
lbm_value f = lbm_cons(t, ENC_SYM_RAW_F_TYPE); |
|
119 |
✗✓ | 19877 |
if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f; |
120 |
19877 |
return lbm_set_ptr_type(f, LBM_TYPE_FLOAT); |
|
121 |
#else |
||
122 |
lbm_uint t = 0; |
||
123 |
memcpy(&t, &x, sizeof(float)); |
||
124 |
return (((lbm_uint)t) << LBM_VAL_SHIFT) | LBM_TYPE_FLOAT; |
||
125 |
#endif |
||
126 |
} |
||
127 |
|||
128 |
#ifndef LBM64 |
||
129 |
8430394 |
static lbm_value enc_64_on_32(uint8_t *source, lbm_uint type_qual, lbm_uint type) { |
|
130 |
8430394 |
lbm_value res = lbm_cons(ENC_SYM_NIL,ENC_SYM_NIL); |
|
131 |
✓✓ | 8430394 |
if (lbm_type_of(res) != LBM_TYPE_SYMBOL) { |
132 |
8428072 |
uint8_t* storage = lbm_malloc(sizeof(uint64_t)); |
|
133 |
✓✓ | 8428072 |
if (storage) { |
134 |
8425364 |
memcpy(storage,source, sizeof(uint64_t)); |
|
135 |
8425364 |
lbm_set_car_and_cdr(res, (lbm_uint)storage, type_qual); |
|
136 |
8425364 |
res = lbm_set_ptr_type(res, type); |
|
137 |
} else { |
||
138 |
2708 |
res = ENC_SYM_MERROR; |
|
139 |
} |
||
140 |
} |
||
141 |
8430394 |
return res; |
|
142 |
} |
||
143 |
#endif |
||
144 |
|||
145 |
4493656 |
lbm_value lbm_enc_i64(int64_t x) { |
|
146 |
#ifndef LBM64 |
||
147 |
4493656 |
return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_I_TYPE, LBM_TYPE_I64); |
|
148 |
#else |
||
149 |
lbm_value u = lbm_cons((uint64_t)x, ENC_SYM_RAW_I_TYPE); |
||
150 |
if (lbm_type_of(u) == LBM_TYPE_SYMBOL) return u; |
||
151 |
return lbm_set_ptr_type(u, LBM_TYPE_I64); |
||
152 |
#endif |
||
153 |
} |
||
154 |
|||
155 |
3371030 |
lbm_value lbm_enc_u64(uint64_t x) { |
|
156 |
#ifndef LBM64 |
||
157 |
3371030 |
return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_U_TYPE, LBM_TYPE_U64); |
|
158 |
#else |
||
159 |
lbm_value u = lbm_cons(x, ENC_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 |
565708 |
lbm_value lbm_enc_double(double x) { |
|
166 |
#ifndef LBM64 |
||
167 |
565708 |
return enc_64_on_32((uint8_t *)&x, ENC_SYM_IND_F_TYPE, LBM_TYPE_DOUBLE); |
|
168 |
#else |
||
169 |
lbm_uint t; |
||
170 |
memcpy(&t, &x, sizeof(double)); |
||
171 |
lbm_value f = lbm_cons(t, ENC_SYM_RAW_F_TYPE); |
||
172 |
if (lbm_type_of(f) == LBM_TYPE_SYMBOL) return f; |
||
173 |
return lbm_set_ptr_type(f, LBM_TYPE_DOUBLE); |
||
174 |
#endif |
||
175 |
} |
||
176 |
|||
177 |
// Type specific (as opposed to the dec_as_X) functions |
||
178 |
// should only be run on values KNOWN to represent a value of the type |
||
179 |
// that the decoder decodes. |
||
180 |
|||
181 |
30521 |
float lbm_dec_float(lbm_value x) { |
|
182 |
#ifndef LBM64 |
||
183 |
float f_tmp; |
||
184 |
30521 |
lbm_uint tmp = lbm_car(x); |
|
185 |
30521 |
memcpy(&f_tmp, &tmp, sizeof(float)); |
|
186 |
30521 |
return f_tmp; |
|
187 |
#else |
||
188 |
uint32_t tmp = (uint32_t)(x >> LBM_VAL_SHIFT); |
||
189 |
float f_tmp; |
||
190 |
memcpy(&f_tmp, &tmp, sizeof(float)); |
||
191 |
return f_tmp; |
||
192 |
#endif |
||
193 |
} |
||
194 |
|||
195 |
564784 |
double lbm_dec_double(lbm_value x) { |
|
196 |
#ifndef LBM64 |
||
197 |
564784 |
double d = 0.0; |
|
198 |
✓✗ | 564784 |
if (lbm_is_ptr(x)) { |
199 |
564784 |
uint32_t *data = (uint32_t*)lbm_ref_cell(x)->car; |
|
200 |
564784 |
memcpy(&d, data, sizeof(double)); |
|
201 |
} |
||
202 |
564784 |
return d; |
|
203 |
#else |
||
204 |
double f_tmp; |
||
205 |
lbm_uint tmp = lbm_car(x); |
||
206 |
memcpy(&f_tmp, &tmp, sizeof(double)); |
||
207 |
return f_tmp; |
||
208 |
#endif |
||
209 |
} |
||
210 |
|||
211 |
7013714 |
uint64_t lbm_dec_u64(lbm_value x) { |
|
212 |
#ifndef LBM64 |
||
213 |
7013714 |
uint64_t u = 0; |
|
214 |
✓✗ | 7013714 |
if (lbm_is_ptr(x)) { |
215 |
7013714 |
uint32_t *data = (uint32_t*)lbm_ref_cell(x)->car; |
|
216 |
7013714 |
memcpy(&u, data, 8); |
|
217 |
} |
||
218 |
7013714 |
return u; |
|
219 |
#else |
||
220 |
return (uint64_t)lbm_car(x); |
||
221 |
#endif |
||
222 |
} |
||
223 |
|||
224 |
9255920 |
int64_t lbm_dec_i64(lbm_value x) { |
|
225 |
#ifndef LBM64 |
||
226 |
9255920 |
int64_t i = 0; |
|
227 |
✓✗ | 9255920 |
if (lbm_is_ptr(x)) { |
228 |
9255920 |
uint32_t *data = (uint32_t*)lbm_ref_cell(x)->car; |
|
229 |
9255920 |
memcpy(&i, data, 8); |
|
230 |
} |
||
231 |
9255920 |
return i; |
|
232 |
#else |
||
233 |
return (int64_t)lbm_car(x); |
||
234 |
#endif |
||
235 |
} |
||
236 |
|||
237 |
790872 |
char *lbm_dec_str(lbm_value val) { |
|
238 |
790872 |
char *res = 0; |
|
239 |
✓✓ | 790872 |
if (lbm_is_array_r(val)) { |
240 |
790676 |
lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(val); |
|
241 |
✓✗ | 790676 |
if (array) res = (char *)array->data; |
242 |
} |
||
243 |
790872 |
return res; |
|
244 |
} |
||
245 |
|||
246 |
599126 |
lbm_array_header_t *lbm_dec_array_r(lbm_value val) { |
|
247 |
599126 |
lbm_array_header_t *array = NULL; |
|
248 |
✓✓ | 599126 |
if (lbm_is_array_r(val)) { |
249 |
597894 |
array = (lbm_array_header_t *)lbm_car(val); |
|
250 |
} |
||
251 |
599126 |
return array; |
|
252 |
} |
||
253 |
|||
254 |
3528 |
lbm_array_header_t *lbm_dec_array_rw(lbm_value val) { |
|
255 |
3528 |
lbm_array_header_t *array = NULL; |
|
256 |
✓✓ | 3528 |
if (lbm_is_array_rw(val)) { |
257 |
3444 |
array = (lbm_array_header_t *)lbm_car(val); |
|
258 |
} |
||
259 |
3528 |
return array; |
|
260 |
} |
||
261 |
|||
262 |
28 |
lbm_array_header_t *lbm_dec_lisp_array_r(lbm_value val) { |
|
263 |
28 |
lbm_array_header_t *array = NULL; |
|
264 |
✓✗ | 28 |
if (lbm_is_lisp_array_r(val)) { |
265 |
28 |
array = (lbm_array_header_t *)lbm_car(val); |
|
266 |
} |
||
267 |
28 |
return array; |
|
268 |
} |
||
269 |
|||
270 |
lbm_array_header_t *lbm_dec_lisp_array_rw(lbm_value val) { |
||
271 |
lbm_array_header_t *array = NULL; |
||
272 |
if (lbm_is_lisp_array_rw(val)) { |
||
273 |
array = (lbm_array_header_t *)lbm_car(val); |
||
274 |
} |
||
275 |
return array; |
||
276 |
} |
||
277 |
|||
278 |
11020237 |
lbm_char_channel_t *lbm_dec_channel(lbm_value val) { |
|
279 |
11020237 |
lbm_char_channel_t *res = NULL; |
|
280 |
|||
281 |
✓✗ | 11020237 |
if (lbm_type_of(val) == LBM_TYPE_CHANNEL) { |
282 |
11020237 |
res = (lbm_char_channel_t *)lbm_car(val); |
|
283 |
} |
||
284 |
11020237 |
return res; |
|
285 |
} |
||
286 |
|||
287 |
lbm_uint lbm_dec_custom(lbm_value val) { |
||
288 |
lbm_uint res = 0; |
||
289 |
if (lbm_type_of(val) == LBM_TYPE_CUSTOM) { |
||
290 |
res = (lbm_uint)lbm_car(val); |
||
291 |
} |
||
292 |
return res; |
||
293 |
} |
||
294 |
|||
295 |
60872 |
uint8_t lbm_dec_as_char(lbm_value a) { |
|
296 |
60872 |
uint8_t r = 0; |
|
297 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
60872 |
switch (lbm_type_of_functional(a)) { |
298 |
60648 |
case LBM_TYPE_CHAR: |
|
299 |
60648 |
r = (uint8_t)lbm_dec_char(a); break; |
|
300 |
28 |
case LBM_TYPE_I: |
|
301 |
28 |
r = (uint8_t)lbm_dec_i(a); break; |
|
302 |
28 |
case LBM_TYPE_U: |
|
303 |
28 |
r = (uint8_t)lbm_dec_u(a); break; |
|
304 |
28 |
case LBM_TYPE_I32: |
|
305 |
28 |
r = (uint8_t)lbm_dec_i32(a); break; |
|
306 |
28 |
case LBM_TYPE_U32: |
|
307 |
28 |
r = (uint8_t)lbm_dec_u32(a); break; |
|
308 |
28 |
case LBM_TYPE_FLOAT: |
|
309 |
28 |
r = (uint8_t)lbm_dec_float(a); break; |
|
310 |
28 |
case LBM_TYPE_I64: |
|
311 |
28 |
r = (uint8_t)lbm_dec_i64(a); break; |
|
312 |
28 |
case LBM_TYPE_U64: |
|
313 |
28 |
r = (uint8_t)lbm_dec_u64(a); break; |
|
314 |
28 |
case LBM_TYPE_DOUBLE: |
|
315 |
28 |
r = (uint8_t) lbm_dec_double(a); break; |
|
316 |
} |
||
317 |
60872 |
return r; |
|
318 |
} |
||
319 |
|||
320 |
8421342 |
uint32_t lbm_dec_as_u32(lbm_value a) { |
|
321 |
8421342 |
uint32_t r = 0; |
|
322 |
✓✓✓✓ ✓✓✓✓ ✓ |
8421342 |
switch (lbm_type_of_functional(a)) { |
323 |
561938 |
case LBM_TYPE_CHAR: |
|
324 |
561938 |
r = (uint32_t)lbm_dec_char(a); break; |
|
325 |
1275571 |
case LBM_TYPE_I: |
|
326 |
1275571 |
r = (uint32_t)lbm_dec_i(a); break; |
|
327 |
1786599 |
case LBM_TYPE_U: |
|
328 |
1786599 |
r = (uint32_t)lbm_dec_u(a); break; |
|
329 |
4795104 |
case LBM_TYPE_I32: /* fall through */ |
|
330 |
case LBM_TYPE_U32: |
||
331 |
4795104 |
r = (uint32_t)lbm_dec_u32(a); break; |
|
332 |
28 |
case LBM_TYPE_FLOAT: |
|
333 |
28 |
r = (uint32_t)lbm_dec_float(a); break; |
|
334 |
28 |
case LBM_TYPE_I64: |
|
335 |
28 |
r = (uint32_t)lbm_dec_i64(a); break; |
|
336 |
84 |
case LBM_TYPE_U64: |
|
337 |
84 |
r = (uint32_t)lbm_dec_u64(a); break; |
|
338 |
28 |
case LBM_TYPE_DOUBLE: |
|
339 |
28 |
r = (uint32_t)lbm_dec_double(a); break; |
|
340 |
} |
||
341 |
8421342 |
return r; |
|
342 |
} |
||
343 |
|||
344 |
206218238 |
int32_t lbm_dec_as_i32(lbm_value a) { |
|
345 |
206218238 |
int32_t r = 0; |
|
346 |
✓✓✓✓ ✓✓✓✓ ✓✓ |
206218238 |
switch (lbm_type_of_functional(a)) { |
347 |
5809904 |
case LBM_TYPE_CHAR: |
|
348 |
5809904 |
r = (int32_t)lbm_dec_char(a); break; |
|
349 |
196725550 |
case LBM_TYPE_I: |
|
350 |
196725550 |
r = (int32_t)lbm_dec_i(a); break; |
|
351 |
196 |
case LBM_TYPE_U: |
|
352 |
196 |
r = (int32_t)lbm_dec_u(a); break; |
|
353 |
3674140 |
case LBM_TYPE_I32: |
|
354 |
3674140 |
r = (int32_t)lbm_dec_i32(a); break; |
|
355 |
28 |
case LBM_TYPE_U32: |
|
356 |
28 |
r = (int32_t)lbm_dec_u32(a); break; |
|
357 |
28 |
case LBM_TYPE_FLOAT: |
|
358 |
28 |
r = (int32_t)lbm_dec_float(a); break; |
|
359 |
56 |
case LBM_TYPE_I64: |
|
360 |
56 |
r = (int32_t)lbm_dec_i64(a); break; |
|
361 |
56 |
case LBM_TYPE_U64: |
|
362 |
56 |
r = (int32_t)lbm_dec_u64(a); break; |
|
363 |
28 |
case LBM_TYPE_DOUBLE: |
|
364 |
28 |
r = (int32_t) lbm_dec_double(a); break; |
|
365 |
} |
||
366 |
206218238 |
return r; |
|
367 |
} |
||
368 |
|||
369 |
6730604 |
int64_t lbm_dec_as_i64(lbm_value a) { |
|
370 |
6730604 |
int64_t r = 0; |
|
371 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
6730604 |
switch (lbm_type_of_functional(a)) { |
372 |
562266 |
case LBM_TYPE_CHAR: |
|
373 |
562266 |
r = (int64_t)lbm_dec_char(a); break; |
|
374 |
1402938 |
case LBM_TYPE_I: |
|
375 |
1402938 |
r = (int64_t)lbm_dec_i(a); break; |
|
376 |
168 |
case LBM_TYPE_U: |
|
377 |
168 |
r = (int64_t)lbm_dec_u(a); break; |
|
378 |
168 |
case LBM_TYPE_I32: |
|
379 |
168 |
r = (int64_t)lbm_dec_i32(a); break; |
|
380 |
168 |
case LBM_TYPE_U32: |
|
381 |
168 |
r = (int64_t)lbm_dec_u32(a); break; |
|
382 |
56 |
case LBM_TYPE_FLOAT: |
|
383 |
56 |
r = (int64_t)lbm_dec_float(a); break; |
|
384 |
4764672 |
case LBM_TYPE_I64: |
|
385 |
4764672 |
r = (int64_t)lbm_dec_i64(a); break; |
|
386 |
112 |
case LBM_TYPE_U64: |
|
387 |
112 |
r = (int64_t)lbm_dec_u64(a); break; |
|
388 |
56 |
case LBM_TYPE_DOUBLE: |
|
389 |
56 |
r = (int64_t) lbm_dec_double(a); break; |
|
390 |
} |
||
391 |
6730604 |
return r; |
|
392 |
} |
||
393 |
|||
394 |
4488314 |
uint64_t lbm_dec_as_u64(lbm_value a) { |
|
395 |
4488314 |
uint64_t r = 0; |
|
396 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
4488314 |
switch (lbm_type_of_functional(a)) { |
397 |
562238 |
case LBM_TYPE_CHAR: |
|
398 |
562238 |
r = (uint64_t)lbm_dec_char(a); break; |
|
399 |
280592 |
case LBM_TYPE_I: |
|
400 |
280592 |
r = (uint64_t)lbm_dec_i(a); break; |
|
401 |
168 |
case LBM_TYPE_U: |
|
402 |
168 |
r = (uint64_t)lbm_dec_u(a); break; |
|
403 |
168 |
case LBM_TYPE_I32: |
|
404 |
168 |
r = (uint64_t)lbm_dec_i32(a); break; |
|
405 |
168 |
case LBM_TYPE_U32: |
|
406 |
168 |
r = (uint64_t)lbm_dec_u32(a); break; |
|
407 |
56 |
case LBM_TYPE_FLOAT: |
|
408 |
56 |
r = (uint64_t)lbm_dec_float(a); break; |
|
409 |
168 |
case LBM_TYPE_I64: |
|
410 |
168 |
r = (uint64_t)lbm_dec_i64(a); break; |
|
411 |
3644700 |
case LBM_TYPE_U64: |
|
412 |
3644700 |
r = (uint64_t)lbm_dec_u64(a); break; |
|
413 |
56 |
case LBM_TYPE_DOUBLE: |
|
414 |
56 |
r = (uint64_t)lbm_dec_double(a); break; |
|
415 |
} |
||
416 |
4488314 |
return r; |
|
417 |
} |
||
418 |
|||
419 |
2324 |
lbm_uint lbm_dec_as_uint(lbm_value a) { |
|
420 |
2324 |
lbm_uint r = 0; |
|
421 |
✗✓✗✗ ✗✗✗✗ ✗✗ |
2324 |
switch (lbm_type_of_functional(a)) { |
422 |
case LBM_TYPE_CHAR: |
||
423 |
r = (lbm_uint)lbm_dec_char(a); break; |
||
424 |
2324 |
case LBM_TYPE_I: |
|
425 |
2324 |
r = (lbm_uint)lbm_dec_i(a); break; |
|
426 |
case LBM_TYPE_U: |
||
427 |
r = (lbm_uint)lbm_dec_u(a); break; |
||
428 |
case LBM_TYPE_I32: |
||
429 |
r = (lbm_uint)lbm_dec_i32(a); break; |
||
430 |
case LBM_TYPE_U32: |
||
431 |
r = (lbm_uint)lbm_dec_u32(a); break; |
||
432 |
case LBM_TYPE_FLOAT: |
||
433 |
r = (lbm_uint)lbm_dec_float(a); break; |
||
434 |
case LBM_TYPE_I64: |
||
435 |
r = (lbm_uint)lbm_dec_i64(a); break; |
||
436 |
case LBM_TYPE_U64: |
||
437 |
r = (lbm_uint) lbm_dec_u64(a); break; |
||
438 |
case LBM_TYPE_DOUBLE: |
||
439 |
r = (lbm_uint)lbm_dec_double(a); break; |
||
440 |
} |
||
441 |
2324 |
return r; |
|
442 |
} |
||
443 |
|||
444 |
644 |
lbm_int lbm_dec_as_int(lbm_value a) { |
|
445 |
644 |
lbm_int r = 0; |
|
446 |
✗✓✗✗ ✗✗✗✗ ✗✗ |
644 |
switch (lbm_type_of_functional(a)) { |
447 |
case LBM_TYPE_CHAR: |
||
448 |
r = (lbm_int)lbm_dec_char(a); break; |
||
449 |
644 |
case LBM_TYPE_I: |
|
450 |
644 |
r = (lbm_int)lbm_dec_i(a); break; |
|
451 |
case LBM_TYPE_U: |
||
452 |
r = (lbm_int)lbm_dec_u(a); break; |
||
453 |
case LBM_TYPE_I32: |
||
454 |
r = (lbm_int)lbm_dec_i32(a); break; |
||
455 |
case LBM_TYPE_U32: |
||
456 |
r = (lbm_int)lbm_dec_u32(a); break; |
||
457 |
case LBM_TYPE_FLOAT: |
||
458 |
r = (lbm_int)lbm_dec_float(a); break; |
||
459 |
case LBM_TYPE_I64: |
||
460 |
r = (lbm_int)lbm_dec_i64(a); break; |
||
461 |
case LBM_TYPE_U64: |
||
462 |
r = (lbm_int)lbm_dec_u64(a); break; |
||
463 |
case LBM_TYPE_DOUBLE: |
||
464 |
r = (lbm_int)lbm_dec_double(a); break; |
||
465 |
} |
||
466 |
644 |
return r; |
|
467 |
} |
||
468 |
|||
469 |
17053 |
float lbm_dec_as_float(lbm_value a) { |
|
470 |
17053 |
float r = 0; |
|
471 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
17053 |
switch (lbm_type_of_functional(a)) { |
472 |
1092 |
case LBM_TYPE_CHAR: |
|
473 |
1092 |
r = (float)lbm_dec_char(a); break; |
|
474 |
1624 |
case LBM_TYPE_I: |
|
475 |
1624 |
r = (float)lbm_dec_i(a); break; |
|
476 |
140 |
case LBM_TYPE_U: |
|
477 |
140 |
r = (float)lbm_dec_u(a); break; |
|
478 |
140 |
case LBM_TYPE_I32: |
|
479 |
140 |
r = (float)lbm_dec_i32(a); break; |
|
480 |
196 |
case LBM_TYPE_U32: |
|
481 |
196 |
r = (float)lbm_dec_u32(a); break; |
|
482 |
13553 |
case LBM_TYPE_FLOAT: |
|
483 |
13553 |
r = (float)lbm_dec_float(a); break; |
|
484 |
140 |
case LBM_TYPE_I64: |
|
485 |
140 |
r = (float)lbm_dec_i64(a); break; |
|
486 |
140 |
case LBM_TYPE_U64: |
|
487 |
140 |
r = (float)lbm_dec_u64(a); break; |
|
488 |
28 |
case LBM_TYPE_DOUBLE: |
|
489 |
28 |
r = (float)lbm_dec_double(a); break; |
|
490 |
} |
||
491 |
17053 |
return r; |
|
492 |
} |
||
493 |
|||
494 |
563944 |
double lbm_dec_as_double(lbm_value a) { |
|
495 |
563944 |
double r = 0; |
|
496 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
563944 |
switch (lbm_type_of_functional(a)) { |
497 |
281168 |
case LBM_TYPE_CHAR: |
|
498 |
281168 |
r = (double)lbm_dec_char(a); break; |
|
499 |
280620 |
case LBM_TYPE_I: |
|
500 |
280620 |
r = (double)lbm_dec_i(a); break; |
|
501 |
140 |
case LBM_TYPE_U: |
|
502 |
140 |
r = (double)lbm_dec_u(a); break; |
|
503 |
140 |
case LBM_TYPE_I32: |
|
504 |
140 |
r = (double)lbm_dec_i32(a); break; |
|
505 |
140 |
case LBM_TYPE_U32: |
|
506 |
140 |
r = (double)lbm_dec_u32(a); break; |
|
507 |
364 |
case LBM_TYPE_FLOAT: |
|
508 |
364 |
r = (double)lbm_dec_float(a); break; |
|
509 |
140 |
case LBM_TYPE_I64: |
|
510 |
140 |
r = (double)lbm_dec_i64(a); break; |
|
511 |
140 |
case LBM_TYPE_U64: |
|
512 |
140 |
r = (double)lbm_dec_u64(a); break; |
|
513 |
1092 |
case LBM_TYPE_DOUBLE: |
|
514 |
1092 |
r = (double)lbm_dec_double(a); break; |
|
515 |
} |
||
516 |
563944 |
return r; |
|
517 |
} |
||
518 |
|||
519 |
/****************************************************/ |
||
520 |
/* HEAP MANAGEMENT */ |
||
521 |
|||
522 |
21588 |
static int generate_freelist(size_t num_cells) { |
|
523 |
21588 |
size_t i = 0; |
|
524 |
|||
525 |
✗✓ | 21588 |
if (!lbm_heap_state.heap) return 0; |
526 |
|||
527 |
21588 |
lbm_heap_state.freelist = lbm_enc_cons_ptr(0); |
|
528 |
|||
529 |
lbm_cons_t *t; |
||
530 |
|||
531 |
// Add all cells to free list |
||
532 |
✓✓ | 200534016 |
for (i = 1; i < num_cells; i ++) { |
533 |
200512428 |
t = lbm_ref_cell(lbm_enc_cons_ptr(i-1)); |
|
534 |
200512428 |
t->car = ENC_SYM_RECOVERED; // all cars in free list are "RECOVERED" |
|
535 |
200512428 |
t->cdr = lbm_enc_cons_ptr(i); |
|
536 |
} |
||
537 |
|||
538 |
// Replace the incorrect pointer at the last cell. |
||
539 |
21588 |
t = lbm_ref_cell(lbm_enc_cons_ptr(num_cells-1)); |
|
540 |
21588 |
t->cdr = ENC_SYM_NIL; |
|
541 |
|||
542 |
21588 |
return 1; |
|
543 |
} |
||
544 |
|||
545 |
347733 |
void lbm_nil_freelist(void) { |
|
546 |
347733 |
lbm_heap_state.freelist = ENC_SYM_NIL; |
|
547 |
347733 |
lbm_heap_state.num_alloc = lbm_heap_state.heap_size; |
|
548 |
347733 |
} |
|
549 |
|||
550 |
21588 |
static void heap_init_state(lbm_cons_t *addr, lbm_uint num_cells, |
|
551 |
lbm_uint* gc_stack_storage, lbm_uint gc_stack_size) { |
||
552 |
21588 |
lbm_heap_state.heap = addr; |
|
553 |
21588 |
lbm_heap_state.heap_bytes = (unsigned int)(num_cells * sizeof(lbm_cons_t)); |
|
554 |
21588 |
lbm_heap_state.heap_size = num_cells; |
|
555 |
|||
556 |
21588 |
lbm_stack_create(&lbm_heap_state.gc_stack, gc_stack_storage, gc_stack_size); |
|
557 |
|||
558 |
21588 |
lbm_heap_state.num_alloc = 0; |
|
559 |
21588 |
lbm_heap_state.num_alloc_arrays = 0; |
|
560 |
21588 |
lbm_heap_state.gc_num = 0; |
|
561 |
21588 |
lbm_heap_state.gc_marked = 0; |
|
562 |
21588 |
lbm_heap_state.gc_recovered = 0; |
|
563 |
21588 |
lbm_heap_state.gc_recovered_arrays = 0; |
|
564 |
21588 |
lbm_heap_state.gc_least_free = num_cells; |
|
565 |
21588 |
lbm_heap_state.gc_last_free = num_cells; |
|
566 |
21588 |
} |
|
567 |
|||
568 |
347733 |
void lbm_heap_new_freelist_length(void) { |
|
569 |
347733 |
lbm_uint l = lbm_heap_state.heap_size - lbm_heap_state.num_alloc; |
|
570 |
347733 |
lbm_heap_state.gc_last_free = l; |
|
571 |
✓✓ | 347733 |
if (l < lbm_heap_state.gc_least_free) |
572 |
3834 |
lbm_heap_state.gc_least_free = l; |
|
573 |
347733 |
} |
|
574 |
|||
575 |
21588 |
int lbm_heap_init(lbm_cons_t *addr, lbm_uint num_cells, |
|
576 |
lbm_uint gc_stack_size) { |
||
577 |
|||
578 |
✗✓ | 21588 |
if (((uintptr_t)addr % 8) != 0) return 0; |
579 |
|||
580 |
21588 |
memset(addr,0, sizeof(lbm_cons_t) * num_cells); |
|
581 |
|||
582 |
21588 |
lbm_uint *gc_stack_storage = (lbm_uint*)lbm_malloc(gc_stack_size * sizeof(lbm_uint)); |
|
583 |
✗✓ | 21588 |
if (gc_stack_storage == NULL) return 0; |
584 |
|||
585 |
21588 |
heap_init_state(addr, num_cells, |
|
586 |
gc_stack_storage, gc_stack_size); |
||
587 |
|||
588 |
21588 |
lbm_heaps[0] = addr; |
|
589 |
|||
590 |
21588 |
return generate_freelist(num_cells); |
|
591 |
} |
||
592 |
|||
593 |
|||
594 |
365203540 |
lbm_value lbm_heap_allocate_cell(lbm_type ptr_type, lbm_value car, lbm_value cdr) { |
|
595 |
lbm_value r; |
||
596 |
365203540 |
lbm_value cell = lbm_heap_state.freelist; |
|
597 |
✓✓ | 365203540 |
if (cell) { |
598 |
365153048 |
lbm_uint heap_ix = lbm_dec_ptr(cell); |
|
599 |
365153048 |
lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr; |
|
600 |
365153048 |
lbm_heap_state.num_alloc++; |
|
601 |
365153048 |
lbm_heap_state.heap[heap_ix].car = car; |
|
602 |
365153048 |
lbm_heap_state.heap[heap_ix].cdr = cdr; |
|
603 |
365153048 |
r = lbm_set_ptr_type(cell, ptr_type); |
|
604 |
} else { |
||
605 |
50492 |
r = ENC_SYM_MERROR; |
|
606 |
} |
||
607 |
365203540 |
return r; |
|
608 |
} |
||
609 |
|||
610 |
1255054 |
lbm_value lbm_heap_allocate_list(lbm_uint n) { |
|
611 |
✓✓ | 1255054 |
if (n == 0) return ENC_SYM_NIL; |
612 |
✓✓ | 1251750 |
if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
613 |
|||
614 |
1250486 |
lbm_value curr = lbm_heap_state.freelist; |
|
615 |
1250486 |
lbm_value res = curr; |
|
616 |
✓✗ | 1250486 |
if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
617 |
|||
618 |
1250486 |
lbm_cons_t *c_cell = NULL; |
|
619 |
1250486 |
lbm_uint count = 0; |
|
620 |
do { |
||
621 |
6465422 |
c_cell = lbm_ref_cell(curr); |
|
622 |
6465422 |
c_cell->car = ENC_SYM_NIL; |
|
623 |
6465422 |
curr = c_cell->cdr; |
|
624 |
6465422 |
count ++; |
|
625 |
✓✓ | 6465422 |
} while (count < n); |
626 |
1250486 |
lbm_heap_state.freelist = curr; |
|
627 |
1250486 |
c_cell->cdr = ENC_SYM_NIL; |
|
628 |
1250486 |
lbm_heap_state.num_alloc+=count; |
|
629 |
1250486 |
return res; |
|
630 |
} |
||
631 |
return ENC_SYM_FATAL_ERROR; |
||
632 |
} |
||
633 |
|||
634 |
622254 |
lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist) { |
|
635 |
✗✓ | 622254 |
if (n == 0) return ENC_SYM_NIL; |
636 |
✓✓ | 622254 |
if (lbm_heap_num_free() < n) return ENC_SYM_MERROR; |
637 |
|||
638 |
618044 |
lbm_value curr = lbm_heap_state.freelist; |
|
639 |
618044 |
lbm_value res = curr; |
|
640 |
✓✗ | 618044 |
if (lbm_type_of(curr) == LBM_TYPE_CONS) { |
641 |
|||
642 |
618044 |
lbm_cons_t *c_cell = NULL; |
|
643 |
618044 |
unsigned int count = 0; |
|
644 |
do { |
||
645 |
1519224 |
c_cell = lbm_ref_cell(curr); |
|
646 |
1519224 |
c_cell->car = va_arg(valist, lbm_value); |
|
647 |
1519224 |
curr = c_cell->cdr; |
|
648 |
1519224 |
count ++; |
|
649 |
✓✓ | 1519224 |
} while (count < n); |
650 |
618044 |
lbm_heap_state.freelist = curr; |
|
651 |
618044 |
c_cell->cdr = ENC_SYM_NIL; |
|
652 |
618044 |
lbm_heap_state.num_alloc+=count; |
|
653 |
618044 |
return res; |
|
654 |
} |
||
655 |
return ENC_SYM_FATAL_ERROR; |
||
656 |
} |
||
657 |
|||
658 |
622254 |
lbm_value lbm_heap_allocate_list_init(unsigned int n, ...) { |
|
659 |
va_list valist; |
||
660 |
622254 |
va_start(valist, n); |
|
661 |
622254 |
lbm_value r = lbm_heap_allocate_list_init_va(n, valist); |
|
662 |
622254 |
va_end(valist); |
|
663 |
622254 |
return r; |
|
664 |
} |
||
665 |
|||
666 |
lbm_uint lbm_heap_num_allocated(void) { |
||
667 |
return lbm_heap_state.num_alloc; |
||
668 |
} |
||
669 |
lbm_uint lbm_heap_size(void) { |
||
670 |
return lbm_heap_state.heap_size; |
||
671 |
} |
||
672 |
|||
673 |
lbm_uint lbm_heap_size_bytes(void) { |
||
674 |
return lbm_heap_state.heap_bytes; |
||
675 |
} |
||
676 |
|||
677 |
252 |
void lbm_get_heap_state(lbm_heap_state_t *res) { |
|
678 |
252 |
*res = lbm_heap_state; |
|
679 |
252 |
} |
|
680 |
|||
681 |
lbm_uint lbm_get_gc_stack_max(void) { |
||
682 |
return lbm_get_max_stack(&lbm_heap_state.gc_stack); |
||
683 |
} |
||
684 |
|||
685 |
lbm_uint lbm_get_gc_stack_size(void) { |
||
686 |
return lbm_heap_state.gc_stack.size; |
||
687 |
} |
||
688 |
|||
689 |
#ifdef USE_GC_PTR_REV |
||
690 |
/* ************************************************************ |
||
691 |
Deutch-Schorr-Waite (DSW) pointer reversal GC for 2-ptr cells |
||
692 |
with a hack-solution for the lisp-array case (n-ptr cells). |
||
693 |
|||
694 |
DSW visits each branch node 3 times compared to 2 times for |
||
695 |
the stack based recursive mark. |
||
696 |
Where the stack based recursive mark performs a stack push/pop, |
||
697 |
DSW rearranges the, current, prev, next and a ptr field on |
||
698 |
the heap. |
||
699 |
|||
700 |
DSW changes the structure of the heap and it introduces an |
||
701 |
invalid pointer (LBM_PTR_NULL) temporarily during marking. |
||
702 |
Since the heap will be "messed up" while marking, a mutex |
||
703 |
is introuded to keep other processes out of the heap while |
||
704 |
marking. |
||
705 |
|||
706 |
TODO: See if the extra index field in arrays can be used |
||
707 |
to mark arrays without resorting to recursive mark calls. |
||
708 |
*/ |
||
709 |
|||
710 |
static inline void value_assign(lbm_value *a, lbm_value b) { |
||
711 |
lbm_value a_old = *a & LBM_GC_MASK; |
||
712 |
*a = a_old | (b & ~LBM_GC_MASK); |
||
713 |
} |
||
714 |
|||
715 |
void lbm_gc_mark_phase_nm(lbm_value root) { |
||
716 |
bool work_to_do = true; |
||
717 |
if (!lbm_is_ptr(root)) return; |
||
718 |
|||
719 |
lbm_value curr = root; |
||
720 |
lbm_value prev = lbm_enc_cons_ptr(LBM_PTR_NULL); |
||
721 |
|||
722 |
while (work_to_do) { |
||
723 |
// follow leftwards pointers |
||
724 |
while (lbm_is_ptr(curr) && |
||
725 |
(lbm_dec_ptr(curr) != LBM_PTR_NULL) && |
||
726 |
((curr & LBM_PTR_TO_CONSTANT_BIT) == 0) && |
||
727 |
!lbm_get_gc_mark(lbm_cdr(curr))) { |
||
728 |
// Mark the cell if not a constant cell |
||
729 |
lbm_cons_t *cell = lbm_ref_cell(curr); |
||
730 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
||
731 |
if (lbm_is_cons_rw(curr)) { |
||
732 |
lbm_value next = 0; |
||
733 |
value_assign(&next, cell->car); |
||
734 |
value_assign(&cell->car, prev); |
||
735 |
value_assign(&prev,curr); |
||
736 |
value_assign(&curr, next); |
||
737 |
} else if (lbm_type_of(curr) == LBM_TYPE_LISPARRAY) { |
||
738 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
||
739 |
lbm_value *arr_data = (lbm_value *)arr->data; |
||
740 |
size_t arr_size = (size_t)arr->size / sizeof(lbm_value); |
||
741 |
// C stack recursion as deep as there are nested arrays. |
||
742 |
// TODO: Try to do this without recursion on the C side. |
||
743 |
for (size_t i = 0; i < arr_size; i ++) { |
||
744 |
lbm_gc_mark_phase_nm(arr_data[i]); |
||
745 |
} |
||
746 |
} |
||
747 |
// Will jump out next iteration as gc mark is set in curr. |
||
748 |
} |
||
749 |
while (lbm_is_ptr(prev) && |
||
750 |
(lbm_dec_ptr(prev) != LBM_PTR_NULL) && |
||
751 |
lbm_get_gc_flag(lbm_car(prev)) ) { |
||
752 |
// clear the flag |
||
753 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
754 |
cell->car = lbm_clr_gc_flag(cell->car); |
||
755 |
lbm_value next = 0; |
||
756 |
value_assign(&next, cell->cdr); |
||
757 |
value_assign(&cell->cdr, curr); |
||
758 |
value_assign(&curr, prev); |
||
759 |
value_assign(&prev, next); |
||
760 |
} |
||
761 |
if (lbm_is_ptr(prev) && |
||
762 |
lbm_dec_ptr(prev) == LBM_PTR_NULL) { |
||
763 |
work_to_do = false; |
||
764 |
} else if (lbm_is_ptr(prev)) { |
||
765 |
// set the flag |
||
766 |
lbm_cons_t *cell = lbm_ref_cell(prev); |
||
767 |
cell->car = lbm_set_gc_flag(cell->car); |
||
768 |
lbm_value next = 0; |
||
769 |
value_assign(&next, cell->car); |
||
770 |
value_assign(&cell->car, curr); |
||
771 |
value_assign(&curr, cell->cdr); |
||
772 |
value_assign(&cell->cdr, next); |
||
773 |
} |
||
774 |
} |
||
775 |
} |
||
776 |
|||
777 |
void lbm_gc_mark_phase(lbm_value root) { |
||
778 |
mutex_lock(&lbm_const_heap_mutex); |
||
779 |
lbm_gc_mark_phase_nm(root); |
||
780 |
mutex_unlock(&lbm_const_heap_mutex); |
||
781 |
} |
||
782 |
|||
783 |
#else |
||
784 |
/* ************************************************************ |
||
785 |
Explicit stack "recursive" mark phase |
||
786 |
|||
787 |
Trees are marked in a left subtree before rigth subtree, car first then cdr, |
||
788 |
way to favor lisp lists. This means that stack will grow slowly when |
||
789 |
marking right-leaning (cdr-recursive) data-structures while left-leaning |
||
790 |
(car-recursive) structures uses a lot of stack. |
||
791 |
|||
792 |
Lisp arrays contain an extra book-keeping field to keep track |
||
793 |
of how far into the array the marking process has gone. |
||
794 |
|||
795 |
TODO: DSW should be used as a last-resort if the GC stack is exhausted. |
||
796 |
If we use DSW as last-resort can we get away with a way smaller |
||
797 |
GC stack and unchanged performance (on sensible programs)? |
||
798 |
*/ |
||
799 |
|||
800 |
extern eval_context_t *ctx_running; |
||
801 |
4810937 |
void lbm_gc_mark_phase(lbm_value root) { |
|
802 |
lbm_value t_ptr; |
||
803 |
4810937 |
lbm_stack_t *s = &lbm_heap_state.gc_stack; |
|
804 |
4810937 |
s->data[s->sp++] = root; |
|
805 |
|||
806 |
✓✓ | 28305716 |
while (!lbm_stack_is_empty(s)) { |
807 |
lbm_value curr; |
||
808 |
23494779 |
lbm_pop(s, &curr); |
|
809 |
|||
810 |
53585134 |
mark_shortcut: |
|
811 |
|||
812 |
✓✓ | 53585134 |
if (!lbm_is_ptr(curr) || |
813 |
✗✓ | 32490084 |
(curr & LBM_PTR_TO_CONSTANT_BIT)) { |
814 |
23035209 |
continue; |
|
815 |
} |
||
816 |
|||
817 |
32490084 |
lbm_cons_t *cell = &lbm_heap_state.heap[lbm_dec_ptr(curr)]; |
|
818 |
|||
819 |
✓✓ | 32490084 |
if (lbm_get_gc_mark(cell->cdr)) { |
820 |
1939277 |
continue; |
|
821 |
} |
||
822 |
|||
823 |
30550807 |
t_ptr = lbm_type_of(curr); |
|
824 |
|||
825 |
// An array is marked in O(N) time using an additional 32bit |
||
826 |
// value per array that keeps track of how far into the array GC |
||
827 |
// has progressed. |
||
828 |
✓✓ | 30550807 |
if (t_ptr == LBM_TYPE_LISPARRAY) { |
829 |
1372 |
lbm_push(s, curr); // put array back as bookkeeping. |
|
830 |
1372 |
lbm_array_header_extended_t *arr = (lbm_array_header_extended_t*)cell->car; |
|
831 |
1372 |
lbm_value *arrdata = (lbm_value *)arr->data; |
|
832 |
1372 |
uint32_t index = arr->index; |
|
833 |
|||
834 |
// Potential optimization. |
||
835 |
// 1. CONS pointers are set to curr and recurse. |
||
836 |
// 2. Any other ptr is marked immediately and index is increased. |
||
837 |
✓✓✓✗ |
1372 |
if (lbm_is_ptr(arrdata[index]) && ((arrdata[index] & LBM_PTR_TO_CONSTANT_BIT) == 0) && |
838 |
✓✓ | 1162 |
!((arrdata[index] & LBM_CONTINUATION_INTERNAL) == LBM_CONTINUATION_INTERNAL)) { |
839 |
1008 |
lbm_cons_t *elt = &lbm_heap_state.heap[lbm_dec_ptr(arrdata[index])]; |
|
840 |
✓✓ | 1008 |
if (!lbm_get_gc_mark(elt->cdr)) { |
841 |
490 |
curr = arrdata[index]; |
|
842 |
490 |
goto mark_shortcut; |
|
843 |
} |
||
844 |
} |
||
845 |
✓✓ | 882 |
if (index < ((arr->size/(sizeof(lbm_value))) - 1)) { |
846 |
714 |
arr->index++; |
|
847 |
714 |
continue; |
|
848 |
} |
||
849 |
|||
850 |
168 |
arr->index = 0; |
|
851 |
168 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
|
852 |
168 |
lbm_heap_state.gc_marked ++; |
|
853 |
168 |
lbm_pop(s, &curr); // Remove array from GC stack as we are done marking it. |
|
854 |
168 |
continue; |
|
855 |
✓✓ | 30549435 |
} else if (t_ptr == LBM_TYPE_CHANNEL) { |
856 |
175040 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
|
857 |
175040 |
lbm_heap_state.gc_marked ++; |
|
858 |
// TODO: Can channels be explicitly freed ? |
||
859 |
✓✗ | 175040 |
if (cell->car != ENC_SYM_NIL) { |
860 |
175040 |
lbm_char_channel_t *chan = (lbm_char_channel_t *)cell->car; |
|
861 |
175040 |
curr = chan->dependency; |
|
862 |
175040 |
goto mark_shortcut; |
|
863 |
} |
||
864 |
continue; |
||
865 |
} |
||
866 |
|||
867 |
30374395 |
cell->cdr = lbm_set_gc_mark(cell->cdr); |
|
868 |
30374395 |
lbm_heap_state.gc_marked ++; |
|
869 |
|||
870 |
✓✓ | 30374395 |
if (t_ptr == LBM_TYPE_CONS) { |
871 |
✓✓ | 29914825 |
if (lbm_is_ptr(cell->cdr)) { |
872 |
✗✓ | 18682638 |
if (!lbm_push(s, cell->cdr)) { |
873 |
lbm_critical_error(); |
||
874 |
break; |
||
875 |
} |
||
876 |
} |
||
877 |
29914825 |
curr = cell->car; |
|
878 |
29914825 |
goto mark_shortcut; // Skip a push/pop |
|
879 |
} |
||
880 |
} |
||
881 |
4810937 |
} |
|
882 |
#endif |
||
883 |
|||
884 |
//Environments are proper lists with a 2 element list stored in each car. |
||
885 |
11488347 |
void lbm_gc_mark_env(lbm_value env) { |
|
886 |
11488347 |
lbm_value curr = env; |
|
887 |
lbm_cons_t *c; |
||
888 |
|||
889 |
✓✓ | 13112509 |
while (lbm_is_ptr(curr)) { |
890 |
1624162 |
c = lbm_ref_cell(curr); |
|
891 |
1624162 |
c->cdr = lbm_set_gc_mark(c->cdr); // mark the environent list structure. |
|
892 |
1624162 |
lbm_cons_t *b = lbm_ref_cell(c->car); |
|
893 |
1624162 |
b->cdr = lbm_set_gc_mark(b->cdr); // mark the binding list head cell. |
|
894 |
1624162 |
lbm_gc_mark_phase(b->cdr); // mark the bound object. |
|
895 |
1624162 |
lbm_heap_state.gc_marked +=2; |
|
896 |
1624162 |
curr = c->cdr; |
|
897 |
} |
||
898 |
11488347 |
} |
|
899 |
|||
900 |
|||
901 |
360891 |
void lbm_gc_mark_aux(lbm_uint *aux_data, lbm_uint aux_size) { |
|
902 |
✓✓ | 6482097 |
for (lbm_uint i = 0; i < aux_size; i ++) { |
903 |
✓✓ | 6121206 |
if (lbm_is_ptr(aux_data[i])) { |
904 |
3701706 |
lbm_type pt_t = lbm_type_of(aux_data[i]); |
|
905 |
3701706 |
lbm_uint pt_v = lbm_dec_ptr(aux_data[i]); |
|
906 |
✓✗✓✓ |
3701706 |
if( pt_t >= LBM_POINTER_TYPE_FIRST && |
907 |
1823338 |
pt_t <= LBM_POINTER_TYPE_LAST && |
|
908 |
✓✗ | 1823338 |
pt_v < lbm_heap_state.heap_size) { |
909 |
1823338 |
lbm_gc_mark_phase(aux_data[i]); |
|
910 |
} |
||
911 |
} |
||
912 |
} |
||
913 |
360891 |
} |
|
914 |
|||
915 |
722946 |
void lbm_gc_mark_roots(lbm_uint *roots, lbm_uint num_roots) { |
|
916 |
✓✓ | 1810583 |
for (lbm_uint i = 0; i < num_roots; i ++) { |
917 |
1087637 |
lbm_gc_mark_phase(roots[i]); |
|
918 |
} |
||
919 |
722946 |
} |
|
920 |
|||
921 |
// Sweep moves non-marked heap objects to the free list. |
||
922 |
347733 |
int lbm_gc_sweep_phase(void) { |
|
923 |
347733 |
unsigned int i = 0; |
|
924 |
347733 |
lbm_cons_t *heap = (lbm_cons_t *)lbm_heap_state.heap; |
|
925 |
|||
926 |
✓✓ | 772375125 |
for (i = 0; i < lbm_heap_state.heap_size; i ++) { |
927 |
✓✓ | 772027392 |
if ( lbm_get_gc_mark(heap[i].cdr)) { |
928 |
33631697 |
heap[i].cdr = lbm_clr_gc_mark(heap[i].cdr); |
|
929 |
} else { |
||
930 |
// Check if this cell is a pointer to an array |
||
931 |
// and free it. |
||
932 |
✓✓ | 738395695 |
if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL) { |
933 |
✓✓✓✓ ✗✓✓ |
52176013 |
switch(heap[i].cdr) { |
934 |
|||
935 |
8364740 |
case ENC_SYM_IND_I_TYPE: /* fall through */ |
|
936 |
case ENC_SYM_IND_U_TYPE: |
||
937 |
case ENC_SYM_IND_F_TYPE: |
||
938 |
8364740 |
lbm_memory_free((lbm_uint*)heap[i].car); |
|
939 |
8364740 |
break; |
|
940 |
1036 |
case ENC_SYM_DEFRAG_ARRAY_TYPE: |
|
941 |
1036 |
lbm_defrag_mem_free((lbm_uint*)heap[i].car); |
|
942 |
1036 |
break; |
|
943 |
294576 |
case ENC_SYM_LISPARRAY_TYPE: /* fall through */ |
|
944 |
case ENC_SYM_ARRAY_TYPE:{ |
||
945 |
294576 |
lbm_array_header_t *arr = (lbm_array_header_t*)heap[i].car; |
|
946 |
294576 |
lbm_memory_free((lbm_uint *)arr->data); |
|
947 |
294576 |
lbm_heap_state.gc_recovered_arrays++; |
|
948 |
294576 |
lbm_memory_free((lbm_uint *)arr); |
|
949 |
294576 |
} break; |
|
950 |
303744 |
case ENC_SYM_CHANNEL_TYPE:{ |
|
951 |
303744 |
lbm_char_channel_t *chan = (lbm_char_channel_t*)heap[i].car; |
|
952 |
303744 |
lbm_memory_free((lbm_uint*)chan->state); |
|
953 |
303744 |
lbm_memory_free((lbm_uint*)chan); |
|
954 |
303744 |
} break; |
|
955 |
case ENC_SYM_CUSTOM_TYPE: { |
||
956 |
lbm_uint *t = (lbm_uint*)heap[i].car; |
||
957 |
lbm_custom_type_destroy(t); |
||
958 |
lbm_memory_free(t); |
||
959 |
} break; |
||
960 |
28 |
case ENC_SYM_DEFRAG_MEM_TYPE: { |
|
961 |
28 |
lbm_uint *ptr = (lbm_uint *)heap[i].car; |
|
962 |
28 |
lbm_defrag_mem_destroy(ptr); |
|
963 |
28 |
} break; |
|
964 |
43211889 |
default: |
|
965 |
43211889 |
break; |
|
966 |
} |
||
967 |
686219682 |
} |
|
968 |
// create pointer to use as new freelist |
||
969 |
738395695 |
lbm_uint addr = lbm_enc_cons_ptr(i); |
|
970 |
|||
971 |
// Clear the "freed" cell. |
||
972 |
738395695 |
heap[i].car = ENC_SYM_RECOVERED; |
|
973 |
738395695 |
heap[i].cdr = lbm_heap_state.freelist; |
|
974 |
738395695 |
lbm_heap_state.freelist = addr; |
|
975 |
738395695 |
lbm_heap_state.num_alloc --; |
|
976 |
738395695 |
lbm_heap_state.gc_recovered ++; |
|
977 |
} |
||
978 |
} |
||
979 |
347733 |
return 1; |
|
980 |
} |
||
981 |
|||
982 |
347733 |
void lbm_gc_state_inc(void) { |
|
983 |
347733 |
lbm_heap_state.gc_num ++; |
|
984 |
347733 |
lbm_heap_state.gc_recovered = 0; |
|
985 |
347733 |
lbm_heap_state.gc_marked = 0; |
|
986 |
347733 |
} |
|
987 |
|||
988 |
// construct, alter and break apart |
||
989 |
364545798 |
lbm_value lbm_cons(lbm_value car, lbm_value cdr) { |
|
990 |
364545798 |
return lbm_heap_allocate_cell(LBM_TYPE_CONS, car, cdr); |
|
991 |
} |
||
992 |
|||
993 |
228980392 |
lbm_value lbm_car(lbm_value c){ |
|
994 |
|||
995 |
✓✓ | 228980392 |
if (lbm_is_ptr(c) ){ |
996 |
228980224 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
997 |
228980224 |
return cell->car; |
|
998 |
} |
||
999 |
|||
1000 |
✓✗ | 168 |
if (lbm_is_symbol_nil(c)) { |
1001 |
168 |
return c; // if nil, return nil. |
|
1002 |
} |
||
1003 |
|||
1004 |
return ENC_SYM_TERROR; |
||
1005 |
} |
||
1006 |
|||
1007 |
// TODO: Many comparisons "is this the nil symbol" can be |
||
1008 |
// streamlined a bit. NIL is 0 and cannot be confused with any other |
||
1009 |
// lbm_value. |
||
1010 |
|||
1011 |
45988 |
lbm_value lbm_caar(lbm_value c) { |
|
1012 |
✓✗ | 45988 |
if (lbm_is_ptr(c)) { |
1013 |
45988 |
lbm_value tmp = lbm_ref_cell(c)->car; |
|
1014 |
|||
1015 |
✓✗ | 45988 |
if (lbm_is_ptr(tmp)) { |
1016 |
45988 |
return lbm_ref_cell(tmp)->car; |
|
1017 |
} else if (lbm_is_symbol_nil(tmp)) { |
||
1018 |
return tmp; |
||
1019 |
} |
||
1020 |
} else if (lbm_is_symbol_nil(c)){ |
||
1021 |
return c; |
||
1022 |
} |
||
1023 |
return ENC_SYM_TERROR; |
||
1024 |
} |
||
1025 |
|||
1026 |
|||
1027 |
11620 |
lbm_value lbm_cadr(lbm_value c) { |
|
1028 |
✓✗ | 11620 |
if (lbm_is_ptr(c)) { |
1029 |
11620 |
lbm_value tmp = lbm_ref_cell(c)->cdr; |
|
1030 |
|||
1031 |
✓✗ | 11620 |
if (lbm_is_ptr(tmp)) { |
1032 |
11620 |
return lbm_ref_cell(tmp)->car; |
|
1033 |
} else if (lbm_is_symbol_nil(tmp)) { |
||
1034 |
return tmp; |
||
1035 |
} |
||
1036 |
} else if (lbm_is_symbol_nil(c)) { |
||
1037 |
return c; |
||
1038 |
} |
||
1039 |
return ENC_SYM_TERROR; |
||
1040 |
} |
||
1041 |
|||
1042 |
112504202 |
lbm_value lbm_cdr(lbm_value c){ |
|
1043 |
✓✓ | 112504202 |
if (lbm_is_ptr(c)) { |
1044 |
111937594 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1045 |
111937594 |
return cell->cdr; |
|
1046 |
} |
||
1047 |
✓✗ | 566608 |
if (lbm_is_symbol_nil(c)) { |
1048 |
566608 |
return ENC_SYM_NIL; // if nil, return nil. |
|
1049 |
} |
||
1050 |
return ENC_SYM_TERROR; |
||
1051 |
} |
||
1052 |
|||
1053 |
lbm_value lbm_cddr(lbm_value c) { |
||
1054 |
if (lbm_is_ptr(c)) { |
||
1055 |
lbm_value tmp = lbm_ref_cell(c)->cdr; |
||
1056 |
if (lbm_is_ptr(tmp)) { |
||
1057 |
return lbm_ref_cell(tmp)->cdr; |
||
1058 |
} |
||
1059 |
} |
||
1060 |
if (lbm_is_symbol_nil(c)) { |
||
1061 |
return ENC_SYM_NIL; |
||
1062 |
} |
||
1063 |
return ENC_SYM_TERROR; |
||
1064 |
} |
||
1065 |
|||
1066 |
6512756 |
int lbm_set_car(lbm_value c, lbm_value v) { |
|
1067 |
6512756 |
int r = 0; |
|
1068 |
|||
1069 |
✓✓ | 6512756 |
if (lbm_type_of(c) == LBM_TYPE_CONS) { |
1070 |
6512728 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1071 |
6512728 |
cell->car = v; |
|
1072 |
6512728 |
r = 1; |
|
1073 |
} |
||
1074 |
6512756 |
return r; |
|
1075 |
} |
||
1076 |
|||
1077 |
99149302 |
int lbm_set_cdr(lbm_value c, lbm_value v) { |
|
1078 |
99149302 |
int r = 0; |
|
1079 |
✓✓ | 99149302 |
if (lbm_is_cons_rw(c)){ |
1080 |
98582778 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1081 |
98582778 |
cell->cdr = v; |
|
1082 |
98582778 |
r = 1; |
|
1083 |
} |
||
1084 |
99149302 |
return r; |
|
1085 |
} |
||
1086 |
|||
1087 |
8428220 |
int lbm_set_car_and_cdr(lbm_value c, lbm_value car_val, lbm_value cdr_val) { |
|
1088 |
8428220 |
int r = 0; |
|
1089 |
✓✗ | 8428220 |
if (lbm_is_cons_rw(c)) { |
1090 |
8428220 |
lbm_cons_t *cell = lbm_ref_cell(c); |
|
1091 |
8428220 |
cell->car = car_val; |
|
1092 |
8428220 |
cell->cdr = cdr_val; |
|
1093 |
8428220 |
r = 1; |
|
1094 |
} |
||
1095 |
8428220 |
return r; |
|
1096 |
} |
||
1097 |
|||
1098 |
/* calculate length of a proper list */ |
||
1099 |
1248594 |
lbm_uint lbm_list_length(lbm_value c) { |
|
1100 |
1248594 |
lbm_uint len = 0; |
|
1101 |
|||
1102 |
✓✓ | 7210750 |
while (lbm_is_cons(c)){ |
1103 |
5962156 |
len ++; |
|
1104 |
5962156 |
c = lbm_cdr(c); |
|
1105 |
} |
||
1106 |
1248594 |
return len; |
|
1107 |
} |
||
1108 |
|||
1109 |
/* calculate the length of a list and check that each element |
||
1110 |
fullfills the predicate pred */ |
||
1111 |
unsigned int lbm_list_length_pred(lbm_value c, bool *pres, bool (*pred)(lbm_value)) { |
||
1112 |
bool res = true; |
||
1113 |
unsigned int len = 0; |
||
1114 |
|||
1115 |
while (lbm_is_cons(c)){ |
||
1116 |
len ++; |
||
1117 |
res = res && pred(lbm_car(c)); |
||
1118 |
c = lbm_cdr(c); |
||
1119 |
} |
||
1120 |
*pres = res; |
||
1121 |
return len; |
||
1122 |
} |
||
1123 |
|||
1124 |
/* reverse a proper list */ |
||
1125 |
lbm_value lbm_list_reverse(lbm_value list) { |
||
1126 |
if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
||
1127 |
return list; |
||
1128 |
} |
||
1129 |
|||
1130 |
lbm_value curr = list; |
||
1131 |
|||
1132 |
lbm_value new_list = ENC_SYM_NIL; |
||
1133 |
while (lbm_is_cons(curr)) { |
||
1134 |
|||
1135 |
new_list = lbm_cons(lbm_car(curr), new_list); |
||
1136 |
if (lbm_type_of(new_list) == LBM_TYPE_SYMBOL) { |
||
1137 |
return ENC_SYM_MERROR; |
||
1138 |
} |
||
1139 |
curr = lbm_cdr(curr); |
||
1140 |
} |
||
1141 |
return new_list; |
||
1142 |
} |
||
1143 |
|||
1144 |
1960 |
lbm_value lbm_list_destructive_reverse(lbm_value list) { |
|
1145 |
✗✓ | 1960 |
if (lbm_type_of(list) == LBM_TYPE_SYMBOL) { |
1146 |
return list; |
||
1147 |
} |
||
1148 |
1960 |
lbm_value curr = list; |
|
1149 |
1960 |
lbm_value last_cell = ENC_SYM_NIL; |
|
1150 |
|||
1151 |
✓✓ | 7168 |
while (lbm_is_cons_rw(curr)) { |
1152 |
5208 |
lbm_value next = lbm_cdr(curr); |
|
1153 |
5208 |
lbm_set_cdr(curr, last_cell); |
|
1154 |
5208 |
last_cell = curr; |
|
1155 |
5208 |
curr = next; |
|
1156 |
} |
||
1157 |
1960 |
return last_cell; |
|
1158 |
} |
||
1159 |
|||
1160 |
|||
1161 |
330056 |
lbm_value lbm_list_copy(int *m, lbm_value list) { |
|
1162 |
330056 |
lbm_value curr = list; |
|
1163 |
330056 |
lbm_uint n = lbm_list_length(list); |
|
1164 |
330056 |
lbm_uint copy_n = n; |
|
1165 |
✓✓✓✓ |
330056 |
if (*m >= 0 && (lbm_uint)*m < n) { |
1166 |
5414 |
copy_n = (lbm_uint)*m; |
|
1167 |
✓✓ | 324642 |
} else if (*m == -1) { |
1168 |
295498 |
*m = (int)n; // TODO: smaller range in target variable. |
|
1169 |
} |
||
1170 |
✓✓ | 330056 |
if (copy_n == 0) return ENC_SYM_NIL; |
1171 |
329832 |
lbm_uint new_list = lbm_heap_allocate_list(copy_n); |
|
1172 |
✓✓ | 329832 |
if (lbm_is_symbol(new_list)) return new_list; |
1173 |
329244 |
lbm_value curr_targ = new_list; |
|
1174 |
|||
1175 |
✓✓✓✓ |
4089516 |
while (lbm_is_cons(curr) && copy_n > 0) { |
1176 |
3760272 |
lbm_value v = lbm_car(curr); |
|
1177 |
3760272 |
lbm_set_car(curr_targ, v); |
|
1178 |
3760272 |
curr_targ = lbm_cdr(curr_targ); |
|
1179 |
3760272 |
curr = lbm_cdr(curr); |
|
1180 |
3760272 |
copy_n --; |
|
1181 |
} |
||
1182 |
|||
1183 |
329244 |
return new_list; |
|
1184 |
} |
||
1185 |
|||
1186 |
// Append for proper lists only |
||
1187 |
// Destructive update of list1. |
||
1188 |
23660 |
lbm_value lbm_list_append(lbm_value list1, lbm_value list2) { |
|
1189 |
|||
1190 |
✓✗✓✗ |
47320 |
if(lbm_is_list_rw(list1) && |
1191 |
23660 |
lbm_is_list(list2)) { |
|
1192 |
|||
1193 |
23660 |
lbm_value curr = list1; |
|
1194 |
✓✓ | 54782 |
while(lbm_type_of(lbm_cdr(curr)) == LBM_TYPE_CONS) { |
1195 |
31122 |
curr = lbm_cdr(curr); |
|
1196 |
} |
||
1197 |
✓✓ | 23660 |
if (lbm_is_symbol_nil(curr)) return list2; |
1198 |
23632 |
lbm_set_cdr(curr, list2); |
|
1199 |
23632 |
return list1; |
|
1200 |
} |
||
1201 |
return ENC_SYM_EERROR; |
||
1202 |
} |
||
1203 |
|||
1204 |
84 |
lbm_value lbm_list_drop(unsigned int n, lbm_value ls) { |
|
1205 |
84 |
lbm_value curr = ls; |
|
1206 |
✓✓✓✓ |
784 |
while (lbm_type_of_functional(curr) == LBM_TYPE_CONS && |
1207 |
n > 0) { |
||
1208 |
700 |
curr = lbm_cdr(curr); |
|
1209 |
700 |
n --; |
|
1210 |
} |
||
1211 |
84 |
return curr; |
|
1212 |
} |
||
1213 |
|||
1214 |
151040 |
lbm_value lbm_index_list(lbm_value l, int32_t n) { |
|
1215 |
151040 |
lbm_value curr = l; |
|
1216 |
|||
1217 |
✓✓ | 151040 |
if (n < 0) { |
1218 |
112 |
int32_t len = (int32_t)lbm_list_length(l); |
|
1219 |
112 |
n = len + n; |
|
1220 |
✗✓ | 112 |
if (n < 0) return ENC_SYM_NIL; |
1221 |
} |
||
1222 |
|||
1223 |
✓✓✓✓ |
227470 |
while (lbm_is_cons(curr) && |
1224 |
n > 0) { |
||
1225 |
76430 |
curr = lbm_cdr(curr); |
|
1226 |
76430 |
n --; |
|
1227 |
} |
||
1228 |
✓✓ | 151040 |
if (lbm_is_cons(curr)) { |
1229 |
151012 |
return lbm_car(curr); |
|
1230 |
} else { |
||
1231 |
28 |
return ENC_SYM_NIL; |
|
1232 |
} |
||
1233 |
} |
||
1234 |
|||
1235 |
// High-level arrays are just bytearrays but with a different tag and pointer type. |
||
1236 |
// These arrays will be inspected by GC and the elements of the array will be marked. |
||
1237 |
|||
1238 |
// Arrays are part of the heap module because their lifespan is managed |
||
1239 |
// by the garbage collector. The data in the array is not stored |
||
1240 |
// in the "heap of cons cells". |
||
1241 |
295956 |
int lbm_heap_allocate_array_base(lbm_value *res, bool byte_array, lbm_uint size){ |
|
1242 |
|||
1243 |
295956 |
lbm_uint tag = ENC_SYM_ARRAY_TYPE; |
|
1244 |
295956 |
lbm_uint type = LBM_TYPE_ARRAY; |
|
1245 |
✓✓ | 295956 |
if (!byte_array) { |
1246 |
812 |
tag = ENC_SYM_LISPARRAY_TYPE; |
|
1247 |
812 |
type = LBM_TYPE_LISPARRAY; |
|
1248 |
812 |
size = sizeof(lbm_value) * size; |
|
1249 |
} |
||
1250 |
295956 |
lbm_array_header_t *array = NULL; |
|
1251 |
✓✓ | 295956 |
if (byte_array) { |
1252 |
295144 |
array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t)); |
|
1253 |
} else { |
||
1254 |
812 |
array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_extended_t)); |
|
1255 |
} |
||
1256 |
|||
1257 |
✓✓ | 295956 |
if (array == NULL) { |
1258 |
58 |
*res = ENC_SYM_MERROR; |
|
1259 |
58 |
return 0; |
|
1260 |
} |
||
1261 |
295898 |
array->data = NULL; |
|
1262 |
✓✓ | 295898 |
if ( size > 0) { |
1263 |
✓✓ | 295814 |
if (!byte_array) { |
1264 |
812 |
lbm_array_header_extended_t *ext_array = (lbm_array_header_extended_t*)array; |
|
1265 |
812 |
ext_array->index = 0; |
|
1266 |
} |
||
1267 |
|||
1268 |
295814 |
array->data = (lbm_uint*)lbm_malloc(size); |
|
1269 |
|||
1270 |
✓✓ | 295814 |
if (array->data == NULL) { |
1271 |
5952 |
lbm_memory_free((lbm_uint*)array); |
|
1272 |
5952 |
*res = ENC_SYM_MERROR; |
|
1273 |
5952 |
return 0; |
|
1274 |
} |
||
1275 |
// It is more important to zero out high-level arrays. |
||
1276 |
// 0 is symbol NIL which is perfectly safe for the GC to inspect. |
||
1277 |
289862 |
memset(array->data, 0, size); |
|
1278 |
} |
||
1279 |
289946 |
array->size = size; |
|
1280 |
|||
1281 |
// allocating a cell for array's heap-presence |
||
1282 |
289946 |
lbm_value cell = lbm_heap_allocate_cell(type, (lbm_uint) array, tag); |
|
1283 |
✓✓ | 289946 |
if (cell == ENC_SYM_MERROR) { |
1284 |
88 |
lbm_memory_free((lbm_uint*)array->data); |
|
1285 |
88 |
lbm_memory_free((lbm_uint*)array); |
|
1286 |
88 |
*res = ENC_SYM_MERROR; |
|
1287 |
88 |
return 0; |
|
1288 |
} |
||
1289 |
289858 |
*res = cell; |
|
1290 |
|||
1291 |
289858 |
lbm_heap_state.num_alloc_arrays ++; |
|
1292 |
|||
1293 |
289858 |
return 1; |
|
1294 |
} |
||
1295 |
|||
1296 |
295144 |
int lbm_heap_allocate_array(lbm_value *res, lbm_uint size){ |
|
1297 |
295144 |
return lbm_heap_allocate_array_base(res, true, size); |
|
1298 |
} |
||
1299 |
|||
1300 |
812 |
int lbm_heap_allocate_lisp_array(lbm_value *res, lbm_uint size) { |
|
1301 |
812 |
return lbm_heap_allocate_array_base(res, false, size); |
|
1302 |
} |
||
1303 |
|||
1304 |
// Convert a C array into an lbm_array. |
||
1305 |
// if the array is in LBM_MEMORY, the lifetime will be managed by the GC after lifting. |
||
1306 |
int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt) { |
||
1307 |
|||
1308 |
lbm_array_header_t *array = NULL; |
||
1309 |
lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE); |
||
1310 |
|||
1311 |
if (cell == ENC_SYM_MERROR) { |
||
1312 |
*value = cell; |
||
1313 |
return 0; |
||
1314 |
} |
||
1315 |
|||
1316 |
array = (lbm_array_header_t*)lbm_malloc(sizeof(lbm_array_header_t)); |
||
1317 |
|||
1318 |
if (array == NULL) { |
||
1319 |
lbm_set_car_and_cdr(cell, ENC_SYM_NIL, ENC_SYM_NIL); |
||
1320 |
*value = ENC_SYM_MERROR; |
||
1321 |
return 0; |
||
1322 |
} |
||
1323 |
|||
1324 |
array->data = (lbm_uint*)data; |
||
1325 |
array->size = num_elt; |
||
1326 |
|||
1327 |
lbm_set_car(cell, (lbm_uint)array); |
||
1328 |
|||
1329 |
cell = lbm_set_ptr_type(cell, LBM_TYPE_ARRAY); |
||
1330 |
*value = cell; |
||
1331 |
return 1; |
||
1332 |
} |
||
1333 |
|||
1334 |
237384 |
lbm_int lbm_heap_array_get_size(lbm_value arr) { |
|
1335 |
|||
1336 |
237384 |
lbm_int r = -1; |
|
1337 |
237384 |
lbm_array_header_t *header = lbm_dec_array_r(arr); |
|
1338 |
✓✗ | 237384 |
if (header) { |
1339 |
237384 |
r = (lbm_int)header->size; |
|
1340 |
} |
||
1341 |
237384 |
return r; |
|
1342 |
} |
||
1343 |
|||
1344 |
118692 |
const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr) { |
|
1345 |
118692 |
uint8_t *r = NULL; |
|
1346 |
118692 |
lbm_array_header_t *header = lbm_dec_array_r(arr); |
|
1347 |
✓✗ | 118692 |
if (header) { |
1348 |
118692 |
r = (uint8_t*)header->data; |
|
1349 |
} |
||
1350 |
118692 |
return r; |
|
1351 |
} |
||
1352 |
|||
1353 |
uint8_t *lbm_heap_array_get_data_rw(lbm_value arr) { |
||
1354 |
uint8_t *r = NULL; |
||
1355 |
lbm_array_header_t *header = lbm_dec_array_rw(arr); |
||
1356 |
if (header) { |
||
1357 |
r = (uint8_t*)header->data; |
||
1358 |
} |
||
1359 |
return r; |
||
1360 |
} |
||
1361 |
|||
1362 |
|||
1363 |
/* Explicitly freeing an array. |
||
1364 |
|||
1365 |
This is a highly unsafe operation and can only be safely |
||
1366 |
used if the heap cell that points to the array has not been made |
||
1367 |
accessible to the program. |
||
1368 |
|||
1369 |
So This function can be used to free an array in case an array |
||
1370 |
is being constructed and some error case appears while doing so |
||
1371 |
If the array still have not become available it can safely be |
||
1372 |
"explicitly" freed. |
||
1373 |
|||
1374 |
The problem is that if the "array" heap-cell is made available to |
||
1375 |
the program, this cell can easily be duplicated and we would have |
||
1376 |
to search the entire heap to find all cells pointing to the array |
||
1377 |
memory in question and "null"-them out before freeing the memory |
||
1378 |
*/ |
||
1379 |
|||
1380 |
112 |
int lbm_heap_explicit_free_array(lbm_value arr) { |
|
1381 |
|||
1382 |
112 |
int r = 0; |
|
1383 |
✓✗✓✗ |
112 |
if (lbm_is_array_rw(arr) && lbm_cdr(arr) == ENC_SYM_ARRAY_TYPE) { |
1384 |
112 |
lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(arr); |
|
1385 |
✗✓ | 112 |
if (header == NULL) { |
1386 |
return 0; |
||
1387 |
} |
||
1388 |
112 |
lbm_memory_free((lbm_uint*)header->data); |
|
1389 |
112 |
lbm_memory_free((lbm_uint*)header); |
|
1390 |
|||
1391 |
112 |
arr = lbm_set_ptr_type(arr, LBM_TYPE_CONS); |
|
1392 |
112 |
lbm_set_car(arr, ENC_SYM_NIL); |
|
1393 |
112 |
lbm_set_cdr(arr, ENC_SYM_NIL); |
|
1394 |
112 |
r = 1; |
|
1395 |
} |
||
1396 |
|||
1397 |
112 |
return r; |
|
1398 |
} |
||
1399 |
|||
1400 |
lbm_uint lbm_size_of(lbm_type t) { |
||
1401 |
lbm_uint s = 0; |
||
1402 |
switch(t) { |
||
1403 |
case LBM_TYPE_BYTE: |
||
1404 |
s = 1; |
||
1405 |
break; |
||
1406 |
case LBM_TYPE_I: /* fall through */ |
||
1407 |
case LBM_TYPE_U: |
||
1408 |
case LBM_TYPE_SYMBOL: |
||
1409 |
s = sizeof(lbm_uint); |
||
1410 |
break; |
||
1411 |
case LBM_TYPE_I32: /* fall through */ |
||
1412 |
case LBM_TYPE_U32: |
||
1413 |
case LBM_TYPE_FLOAT: |
||
1414 |
s = 4; |
||
1415 |
break; |
||
1416 |
case LBM_TYPE_I64: /* fall through */ |
||
1417 |
case LBM_TYPE_U64: |
||
1418 |
case LBM_TYPE_DOUBLE: |
||
1419 |
s = 8; |
||
1420 |
break; |
||
1421 |
} |
||
1422 |
return s; |
||
1423 |
} |
||
1424 |
|||
1425 |
static bool dummy_flash_write(lbm_uint ix, lbm_uint val) { |
||
1426 |
(void)ix; |
||
1427 |
(void)val; |
||
1428 |
return false; |
||
1429 |
} |
||
1430 |
|||
1431 |
static const_heap_write_fun const_heap_write = dummy_flash_write; |
||
1432 |
|||
1433 |
21588 |
int lbm_const_heap_init(const_heap_write_fun w_fun, |
|
1434 |
lbm_const_heap_t *heap, |
||
1435 |
lbm_uint *addr, |
||
1436 |
lbm_uint num_words) { |
||
1437 |
✗✓ | 21588 |
if (((uintptr_t)addr % 4) != 0) return 0; |
1438 |
✗✓ | 21588 |
if ((num_words % 2) != 0) return 0; |
1439 |
|||
1440 |
✓✗ | 21588 |
if (!lbm_const_heap_mutex_initialized) { |
1441 |
21588 |
mutex_init(&lbm_const_heap_mutex); |
|
1442 |
21588 |
lbm_const_heap_mutex_initialized = true; |
|
1443 |
} |
||
1444 |
|||
1445 |
✓✗ | 21588 |
if (!lbm_mark_mutex_initialized) { |
1446 |
21588 |
mutex_init(&lbm_mark_mutex); |
|
1447 |
21588 |
lbm_mark_mutex_initialized = true; |
|
1448 |
} |
||
1449 |
|||
1450 |
21588 |
const_heap_write = w_fun; |
|
1451 |
|||
1452 |
21588 |
heap->heap = addr; |
|
1453 |
21588 |
heap->size = num_words; |
|
1454 |
21588 |
heap->next = 0; |
|
1455 |
|||
1456 |
21588 |
lbm_const_heap_state = heap; |
|
1457 |
// ref_cell views the lbm_uint array as an lbm_cons_t array |
||
1458 |
21588 |
lbm_heaps[1] = (lbm_cons_t*)addr; |
|
1459 |
21588 |
return 1; |
|
1460 |
} |
||
1461 |
|||
1462 |
2408 |
lbm_flash_status lbm_allocate_const_cell(lbm_value *res) { |
|
1463 |
2408 |
lbm_flash_status r = LBM_FLASH_FULL; |
|
1464 |
|||
1465 |
2408 |
mutex_lock(&lbm_const_heap_mutex); |
|
1466 |
// waste a cell if we have ended up unaligned after writing an array to flash. |
||
1467 |
✓✓ | 2408 |
if (lbm_const_heap_state->next % 2 == 1) { |
1468 |
28 |
lbm_const_heap_state->next++; |
|
1469 |
} |
||
1470 |
|||
1471 |
✓✗ | 2408 |
if (lbm_const_heap_state && |
1472 |
✓✗ | 2408 |
(lbm_const_heap_state->next+1) < lbm_const_heap_state->size) { |
1473 |
// A cons cell uses two words. |
||
1474 |
2408 |
lbm_value cell = lbm_const_heap_state->next; |
|
1475 |
2408 |
lbm_const_heap_state->next += 2; |
|
1476 |
2408 |
*res = (cell << LBM_ADDRESS_SHIFT) | LBM_PTR_BIT | LBM_TYPE_CONS | LBM_PTR_TO_CONSTANT_BIT; |
|
1477 |
2408 |
r = LBM_FLASH_WRITE_OK; |
|
1478 |
} |
||
1479 |
2408 |
mutex_unlock(&lbm_const_heap_mutex); |
|
1480 |
2408 |
return r; |
|
1481 |
} |
||
1482 |
|||
1483 |
28 |
lbm_flash_status lbm_allocate_const_raw(lbm_uint nwords, lbm_uint *res) { |
|
1484 |
28 |
lbm_flash_status r = LBM_FLASH_FULL; |
|
1485 |
|||
1486 |
✓✗ | 28 |
if (lbm_const_heap_state && |
1487 |
✓✗ | 28 |
(lbm_const_heap_state->next + nwords) < lbm_const_heap_state->size) { |
1488 |
28 |
lbm_uint ix = lbm_const_heap_state->next; |
|
1489 |
28 |
*res = (lbm_uint)&lbm_const_heap_state->heap[ix]; |
|
1490 |
28 |
lbm_const_heap_state->next += nwords; |
|
1491 |
28 |
r = LBM_FLASH_WRITE_OK; |
|
1492 |
} |
||
1493 |
28 |
return r; |
|
1494 |
} |
||
1495 |
|||
1496 |
462 |
lbm_flash_status lbm_write_const_raw(lbm_uint *data, lbm_uint n, lbm_uint *res) { |
|
1497 |
|||
1498 |
462 |
lbm_flash_status r = LBM_FLASH_FULL; |
|
1499 |
|||
1500 |
✓✗ | 462 |
if (lbm_const_heap_state && |
1501 |
✓✗ | 462 |
(lbm_const_heap_state->next + n) < lbm_const_heap_state->size) { |
1502 |
462 |
lbm_uint ix = lbm_const_heap_state->next; |
|
1503 |
|||
1504 |
✓✓ | 1442 |
for (unsigned int i = 0; i < n; i ++) { |
1505 |
✗✓ | 980 |
if (!const_heap_write(ix + i, ((lbm_uint*)data)[i])) |
1506 |
return LBM_FLASH_WRITE_ERROR; |
||
1507 |
} |
||
1508 |
462 |
lbm_const_heap_state->next += n; |
|
1509 |
462 |
*res = (lbm_uint)&lbm_const_heap_state->heap[ix]; |
|
1510 |
462 |
r = LBM_FLASH_WRITE_OK; |
|
1511 |
} |
||
1512 |
462 |
return r; |
|
1513 |
} |
||
1514 |
|||
1515 |
84 |
lbm_flash_status lbm_const_write(lbm_uint *tgt, lbm_uint val) { |
|
1516 |
|||
1517 |
✓✗ | 84 |
if (lbm_const_heap_state) { |
1518 |
84 |
lbm_uint flash = (lbm_uint)lbm_const_heap_state->heap; |
|
1519 |
84 |
lbm_uint ix = (((lbm_uint)tgt - flash) / sizeof(lbm_uint)); // byte address to ix |
|
1520 |
✓✗ | 84 |
if (const_heap_write(ix, val)) { |
1521 |
84 |
return LBM_FLASH_WRITE_OK; |
|
1522 |
} |
||
1523 |
return LBM_FLASH_WRITE_ERROR; |
||
1524 |
} |
||
1525 |
return LBM_FLASH_FULL; |
||
1526 |
} |
||
1527 |
|||
1528 |
2408 |
lbm_flash_status write_const_cdr(lbm_value cell, lbm_value val) { |
|
1529 |
2408 |
lbm_uint addr = lbm_dec_ptr(cell); |
|
1530 |
✓✗ | 2408 |
if (const_heap_write(addr+1, val)) |
1531 |
2408 |
return LBM_FLASH_WRITE_OK; |
|
1532 |
return LBM_FLASH_WRITE_ERROR; |
||
1533 |
} |
||
1534 |
|||
1535 |
2408 |
lbm_flash_status write_const_car(lbm_value cell, lbm_value val) { |
|
1536 |
2408 |
lbm_uint addr = lbm_dec_ptr(cell); |
|
1537 |
✓✗ | 2408 |
if (const_heap_write(addr, val)) |
1538 |
2408 |
return LBM_FLASH_WRITE_OK; |
|
1539 |
return LBM_FLASH_WRITE_ERROR; |
||
1540 |
} |
||
1541 |
|||
1542 |
lbm_uint lbm_flash_memory_usage(void) { |
||
1543 |
return lbm_const_heap_state->next; |
||
1544 |
} |
Generated by: GCOVR (Version 4.2) |