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