GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
Copyright 2023, 2024 Joel Svensson svenssonjoel@yahoo.se |
||
3 |
2023 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 <lbm_flat_value.h> |
||
20 |
#include <eval_cps.h> |
||
21 |
#include <stack.h> |
||
22 |
|||
23 |
#include <setjmp.h> |
||
24 |
|||
25 |
// ------------------------------------------------------------ |
||
26 |
// Access to GC from eval_cps |
||
27 |
int lbm_perform_gc(void); |
||
28 |
|||
29 |
|||
30 |
// ------------------------------------------------------------ |
||
31 |
// Flatteners |
||
32 |
|||
33 |
42189 |
bool lbm_start_flatten(lbm_flat_value_t *v, size_t buffer_size) { |
|
34 |
42189 |
bool res = false; |
|
35 |
42189 |
uint8_t *data = lbm_malloc_reserve(buffer_size); |
|
36 |
✓✗ | 42189 |
if (data) { |
37 |
42189 |
v->buf = data; |
|
38 |
42189 |
v->buf_size = buffer_size; |
|
39 |
42189 |
v->buf_pos = 0; |
|
40 |
42189 |
res = true; |
|
41 |
} |
||
42 |
42189 |
return res; |
|
43 |
} |
||
44 |
|||
45 |
7651 |
bool lbm_finish_flatten(lbm_flat_value_t *v) { |
|
46 |
lbm_uint size_words; |
||
47 |
✗✓ | 7651 |
if (v->buf_pos % sizeof(lbm_uint) == 0) { |
48 |
size_words = v->buf_pos / sizeof(lbm_uint); |
||
49 |
} else { |
||
50 |
7651 |
size_words = (v->buf_pos / sizeof(lbm_uint)) + 1; |
|
51 |
} |
||
52 |
✓✓ | 7651 |
if (v->buf_size <= size_words * sizeof(lbm_uint)) return true; |
53 |
7623 |
v->buf_size = size_words * sizeof(lbm_uint); |
|
54 |
7623 |
return (lbm_memory_shrink((lbm_uint*)v->buf, size_words) >= 0); |
|
55 |
} |
||
56 |
|||
57 |
422513 |
static bool write_byte(lbm_flat_value_t *v, uint8_t b) { |
|
58 |
422513 |
bool res = false; |
|
59 |
✓✗ | 422513 |
if (v->buf_size >= v->buf_pos + 1) { |
60 |
422513 |
v->buf[v->buf_pos++] = b; |
|
61 |
422513 |
res = true; |
|
62 |
} |
||
63 |
422513 |
return res; |
|
64 |
} |
||
65 |
|||
66 |
181776 |
static bool write_bytes(lbm_flat_value_t *v, uint8_t *data,lbm_uint num_bytes) { |
|
67 |
181776 |
bool res = false; |
|
68 |
✓✗ | 181776 |
if (v->buf_size >= v->buf_pos + num_bytes) { |
69 |
181776 |
memcpy(v->buf + v->buf_pos, data, num_bytes); |
|
70 |
181776 |
v->buf_pos += num_bytes; |
|
71 |
181776 |
res = true; |
|
72 |
} |
||
73 |
181776 |
return res; |
|
74 |
} |
||
75 |
|||
76 |
238161 |
static bool write_word(lbm_flat_value_t *v, uint32_t w) { |
|
77 |
238161 |
bool res = false; |
|
78 |
✓✗ | 238161 |
if (v->buf_size >= v->buf_pos + 4) { |
79 |
238161 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 24); |
|
80 |
238161 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 16); |
|
81 |
238161 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 8); |
|
82 |
238161 |
v->buf[v->buf_pos++] = (uint8_t)w; |
|
83 |
238161 |
res = true; |
|
84 |
} |
||
85 |
238161 |
return res; |
|
86 |
} |
||
87 |
|||
88 |
84 |
static bool write_dword(lbm_flat_value_t *v, uint64_t w) { |
|
89 |
84 |
bool res = false; |
|
90 |
✓✗ | 84 |
if (v->buf_size >= v->buf_pos + 8) { |
91 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 56); |
|
92 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 48); |
|
93 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 40); |
|
94 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 32); |
|
95 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 24); |
|
96 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 16); |
|
97 |
84 |
v->buf[v->buf_pos++] = (uint8_t)(w >> 8); |
|
98 |
84 |
v->buf[v->buf_pos++] = (uint8_t)w; |
|
99 |
84 |
res = true; |
|
100 |
} |
||
101 |
84 |
return res; |
|
102 |
} |
||
103 |
|||
104 |
319452 |
bool f_cons(lbm_flat_value_t *v) { |
|
105 |
319452 |
bool res = false; |
|
106 |
✓✗ | 319452 |
if (v->buf_size >= v->buf_pos + 1) { |
107 |
319452 |
v->buf[v->buf_pos++] = S_CONS; |
|
108 |
319452 |
res = true; |
|
109 |
} |
||
110 |
319452 |
return res; |
|
111 |
} |
||
112 |
|||
113 |
84 |
bool f_lisp_array(lbm_flat_value_t *v, uint32_t size) { |
|
114 |
// arrays are smaller than 2^32 elements long |
||
115 |
84 |
bool res = true; |
|
116 |
✓✗✓✗ |
84 |
res = res && write_byte(v, S_LBM_LISP_ARRAY); |
117 |
✓✗✓✗ |
84 |
res = res && write_word(v, size); // number of elements. |
118 |
84 |
return res; |
|
119 |
} |
||
120 |
|||
121 |
5891 |
bool f_sym(lbm_flat_value_t *v, lbm_uint sym_id) { |
|
122 |
5891 |
bool res = true; |
|
123 |
✓✗✓✗ |
5891 |
res = res && write_byte(v,S_SYM_VALUE); |
124 |
#ifndef LBM64 |
||
125 |
✓✗✓✗ |
5891 |
res = res && write_word(v,sym_id); |
126 |
#else |
||
127 |
res = res && write_dword(v,sym_id); |
||
128 |
#endif |
||
129 |
5891 |
return res; |
|
130 |
} |
||
131 |
|||
132 |
63028 |
bool f_sym_string(lbm_flat_value_t *v, char *str) { |
|
133 |
63028 |
bool res = false; |
|
134 |
✓✗ | 63028 |
if (str) { |
135 |
63028 |
lbm_uint sym_bytes = strlen(str) + 1; |
|
136 |
✓✗✓✗ |
126056 |
if (write_byte(v, S_SYM_STRING) && |
137 |
63028 |
write_bytes(v, (uint8_t*)str, sym_bytes)) { |
|
138 |
63028 |
res = true; |
|
139 |
} |
||
140 |
} |
||
141 |
63028 |
return res; |
|
142 |
} |
||
143 |
|||
144 |
// Potentially a difference between 32/64 bit version. |
||
145 |
// strlen returns size_t which is different on 32/64 bit platforms. |
||
146 |
62972 |
int f_sym_string_bytes(lbm_value sym) { |
|
147 |
62972 |
int res = FLATTEN_VALUE_ERROR_FATAL; |
|
148 |
✓✗ | 62972 |
if (lbm_is_symbol(sym)) { |
149 |
62972 |
lbm_uint s = lbm_dec_sym(sym); |
|
150 |
62972 |
char *sym_str = (char*)lbm_get_name_by_symbol(s); |
|
151 |
✓✗ | 62972 |
if (sym_str) { |
152 |
62972 |
lbm_uint sym_bytes = strlen(sym_str) + 1; |
|
153 |
62972 |
res = (int)sym_bytes; |
|
154 |
} |
||
155 |
} |
||
156 |
62972 |
return res; |
|
157 |
} |
||
158 |
|||
159 |
45374 |
bool f_i(lbm_flat_value_t *v, lbm_int i) { |
|
160 |
45374 |
bool res = true; |
|
161 |
#ifndef LBM64 |
||
162 |
✓✗✓✗ |
45374 |
res = res && write_byte(v,S_I28_VALUE); |
163 |
✓✗✓✗ |
45374 |
res = res && write_word(v,(uint32_t)i); |
164 |
#else |
||
165 |
res = res && write_byte(v,S_I56_VALUE); |
||
166 |
res = res && write_dword(v, (uint64_t)i); |
||
167 |
#endif |
||
168 |
45374 |
return res; |
|
169 |
} |
||
170 |
|||
171 |
28 |
bool f_u(lbm_flat_value_t *v, lbm_uint u) { |
|
172 |
28 |
bool res = true; |
|
173 |
#ifndef LBM64 |
||
174 |
✓✗✓✗ |
28 |
res = res && write_byte(v,S_U28_VALUE); |
175 |
✓✗✓✗ |
28 |
res = res && write_word(v,(uint32_t)u); |
176 |
#else |
||
177 |
res = res && write_byte(v,S_U56_VALUE); |
||
178 |
res = res && write_dword(v,(uint64_t)u); |
||
179 |
#endif |
||
180 |
28 |
return res; |
|
181 |
} |
||
182 |
|||
183 |
60620 |
bool f_b(lbm_flat_value_t *v, uint8_t b) { |
|
184 |
60620 |
bool res = true; |
|
185 |
✓✗✓✗ |
60620 |
res = res && write_byte(v,S_BYTE_VALUE); |
186 |
✓✗✓✗ |
60620 |
res = res && write_byte(v,b); |
187 |
60620 |
return res; |
|
188 |
} |
||
189 |
|||
190 |
29274 |
bool f_i32(lbm_flat_value_t *v, int32_t w) { |
|
191 |
29274 |
bool res = true; |
|
192 |
✓✗✓✗ |
29274 |
res = res && write_byte(v, S_I32_VALUE); |
193 |
✓✗✓✗ |
29274 |
res = res && write_word(v, (uint32_t)w); |
194 |
29274 |
return res; |
|
195 |
} |
||
196 |
|||
197 |
31122 |
bool f_u32(lbm_flat_value_t *v, uint32_t w) { |
|
198 |
31122 |
bool res = true; |
|
199 |
✓✗✓✗ |
31122 |
res = res && write_byte(v, S_U32_VALUE); |
200 |
✓✗✓✗ |
31122 |
res = res && write_word(v, w); |
201 |
31122 |
return res; |
|
202 |
} |
||
203 |
|||
204 |
7640 |
bool f_float(lbm_flat_value_t *v, float f) { |
|
205 |
7640 |
bool res = true; |
|
206 |
✓✗✓✗ |
7640 |
res = res && write_byte(v, S_FLOAT_VALUE); |
207 |
uint32_t u; |
||
208 |
7640 |
memcpy(&u, &f, sizeof(uint32_t)); |
|
209 |
✓✗✓✗ |
7640 |
res = res && write_word(v, (uint32_t)u); |
210 |
7640 |
return res; |
|
211 |
} |
||
212 |
|||
213 |
28 |
bool f_double(lbm_flat_value_t *v, double d) { |
|
214 |
28 |
bool res = true; |
|
215 |
✓✗✓✗ |
28 |
res = res && write_byte(v, S_DOUBLE_VALUE); |
216 |
uint64_t u; |
||
217 |
28 |
memcpy(&u, &d, sizeof(uint64_t)); |
|
218 |
✓✗✓✗ |
28 |
res = res && write_dword(v, u); |
219 |
28 |
return res; |
|
220 |
} |
||
221 |
|||
222 |
28 |
bool f_i64(lbm_flat_value_t *v, int64_t w) { |
|
223 |
28 |
bool res = true; |
|
224 |
✓✗✓✗ |
28 |
res = res && write_byte(v, S_I64_VALUE); |
225 |
✓✗✓✗ |
28 |
res = res && write_dword(v, (uint64_t)w); |
226 |
28 |
return res; |
|
227 |
} |
||
228 |
|||
229 |
28 |
bool f_u64(lbm_flat_value_t *v, uint64_t w) { |
|
230 |
28 |
bool res = true; |
|
231 |
✓✗✓✗ |
28 |
res = res && write_byte(v, S_U64_VALUE); |
232 |
✓✗✓✗ |
28 |
res = res && write_dword(v, w); |
233 |
28 |
return res; |
|
234 |
} |
||
235 |
|||
236 |
// num_bytes is specifically an uint32_t |
||
237 |
118748 |
bool f_lbm_array(lbm_flat_value_t *v, uint32_t num_bytes, uint8_t *data) { |
|
238 |
118748 |
bool res = write_byte(v, S_LBM_ARRAY); |
|
239 |
✓✗✓✗ |
118748 |
res = res && write_word(v, num_bytes); |
240 |
✓✗✓✗ |
118748 |
res = res && write_bytes(v, data, num_bytes); |
241 |
118748 |
return res; |
|
242 |
} |
||
243 |
|||
244 |
static int flatten_maximum_depth = FLATTEN_VALUE_MAXIMUM_DEPTH; |
||
245 |
|||
246 |
28 |
void lbm_set_max_flatten_depth(int depth) { |
|
247 |
28 |
flatten_maximum_depth = depth; |
|
248 |
28 |
} |
|
249 |
|||
250 |
28 |
void flatten_error(jmp_buf jb, int val) { |
|
251 |
28 |
longjmp(jb, val); |
|
252 |
} |
||
253 |
|||
254 |
661962 |
int flatten_value_size_internal(jmp_buf jb, lbm_value v, int depth) { |
|
255 |
✓✓ | 661962 |
if (depth > flatten_maximum_depth) { |
256 |
28 |
flatten_error(jb, FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH); |
|
257 |
} |
||
258 |
|||
259 |
661934 |
lbm_uint t = lbm_type_of(v); |
|
260 |
✓✓✓✗ |
661934 |
if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) { |
261 |
// Clear constant bit, it is irrelevant to flattening |
||
262 |
492940 |
t = t & ~(LBM_PTR_TO_CONSTANT_BIT); |
|
263 |
} |
||
264 |
|||
265 |
✓✓✓✓ ✓✓✓✓ ✓ |
661934 |
switch (t) { |
266 |
313600 |
case LBM_TYPE_CONS: { |
|
267 |
313600 |
int res = 0; |
|
268 |
313600 |
int s1 = flatten_value_size_internal(jb,lbm_car(v), depth + 1); |
|
269 |
✓✗ | 313516 |
if (s1 > 0) { |
270 |
313516 |
int s2 = flatten_value_size_internal(jb,lbm_cdr(v), depth + 1); |
|
271 |
✓✗ | 313516 |
if (s2 > 0) { |
272 |
313516 |
res = (1 + s1 + s2); |
|
273 |
} |
||
274 |
} |
||
275 |
313516 |
return res; |
|
276 |
} |
||
277 |
84 |
case LBM_TYPE_LISPARRAY: { |
|
278 |
84 |
int sum = 4 + 1; // sizeof(uint32_t) + 1; |
|
279 |
84 |
lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(v); |
|
280 |
84 |
lbm_value *arrdata = (lbm_value*)header->data; |
|
281 |
84 |
lbm_uint size = header->size / sizeof(lbm_value); |
|
282 |
✓✓ | 336 |
for (lbm_uint i = 0; i < size; i ++ ) { |
283 |
252 |
sum += flatten_value_size_internal(jb, arrdata[i], depth + 1); |
|
284 |
} |
||
285 |
84 |
return sum; |
|
286 |
} |
||
287 |
60620 |
case LBM_TYPE_BYTE: |
|
288 |
60620 |
return 1 + 1; |
|
289 |
45402 |
case LBM_TYPE_U: /* fall through */ |
|
290 |
case LBM_TYPE_I: |
||
291 |
#ifndef LBM64 |
||
292 |
45402 |
return 1 + 4; |
|
293 |
#else |
||
294 |
return 1 + 8; |
||
295 |
#endif |
||
296 |
60452 |
case LBM_TYPE_U32: /* fall through */ |
|
297 |
case LBM_TYPE_I32: |
||
298 |
case LBM_TYPE_FLOAT: |
||
299 |
60452 |
return 1 + 4; |
|
300 |
84 |
case LBM_TYPE_U64: /* fall through */ |
|
301 |
case LBM_TYPE_I64: |
||
302 |
case LBM_TYPE_DOUBLE: |
||
303 |
84 |
return 1 + 8; |
|
304 |
62972 |
case LBM_TYPE_SYMBOL: { |
|
305 |
62972 |
int s = f_sym_string_bytes(v); |
|
306 |
✓✗ | 62972 |
if (s > 0) return 1 + s; |
307 |
flatten_error(jb, (int)s); |
||
308 |
} return 0; // already terminated with error |
||
309 |
118692 |
case LBM_TYPE_ARRAY: { |
|
310 |
// Platform dependent size. |
||
311 |
// TODO: Something needs to be done to these inconsistencies. |
||
312 |
118692 |
lbm_int s = lbm_heap_array_get_size(v); |
|
313 |
✓✗ | 118692 |
if (s > 0) |
314 |
118692 |
return 1 + 4 + (int)s; |
|
315 |
flatten_error(jb, (int)s); |
||
316 |
} return 0; // already terminated with error |
||
317 |
28 |
default: |
|
318 |
28 |
return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED; |
|
319 |
} |
||
320 |
} |
||
321 |
|||
322 |
34594 |
int flatten_value_size(lbm_value v, int depth) { |
|
323 |
jmp_buf jb; |
||
324 |
34594 |
int r = setjmp(jb); |
|
325 |
✓✓ | 34622 |
if (r != 0) { |
326 |
28 |
return r; |
|
327 |
} |
||
328 |
34594 |
return flatten_value_size_internal(jb, v, depth); |
|
329 |
} |
||
330 |
|||
331 |
661822 |
int flatten_value_c(lbm_flat_value_t *fv, lbm_value v) { |
|
332 |
|||
333 |
661822 |
lbm_uint t = lbm_type_of(v); |
|
334 |
✓✓✓✗ |
661822 |
if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) { |
335 |
// Clear constant bit, it is irrelevant to flattening |
||
336 |
492828 |
t = t & ~(LBM_PTR_TO_CONSTANT_BIT); |
|
337 |
} |
||
338 |
|||
339 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✗ |
661822 |
switch (t) { |
340 |
313516 |
case LBM_TYPE_CONS: { |
|
341 |
313516 |
bool res = true; |
|
342 |
✓✗✓✗ |
313516 |
res = res && f_cons(fv); |
343 |
✓✗ | 313516 |
if (res) { |
344 |
313516 |
int fv_r = flatten_value_c(fv, lbm_car(v)); |
|
345 |
✓✗ | 313516 |
if (fv_r == FLATTEN_VALUE_OK) { |
346 |
313516 |
fv_r = flatten_value_c(fv, lbm_cdr(v)); |
|
347 |
} |
||
348 |
313516 |
return fv_r; |
|
349 |
} |
||
350 |
}break; |
||
351 |
84 |
case LBM_TYPE_LISPARRAY: { |
|
352 |
84 |
lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(v); |
|
353 |
84 |
lbm_value *arrdata = (lbm_value*)header->data; |
|
354 |
84 |
lbm_uint size = header->size / sizeof(lbm_value); |
|
355 |
✗✓ | 84 |
if (!f_lisp_array(fv, size)) return FLATTEN_VALUE_ERROR_NOT_ENOUGH_MEMORY; |
356 |
84 |
int fv_r = FLATTEN_VALUE_OK; |
|
357 |
✓✓ | 336 |
for (lbm_uint i = 0; i < size; i ++ ) { |
358 |
252 |
fv_r = flatten_value_c(fv, arrdata[i]); |
|
359 |
✗✓ | 252 |
if (fv_r != FLATTEN_VALUE_OK) { |
360 |
break; |
||
361 |
} |
||
362 |
} |
||
363 |
84 |
return fv_r; |
|
364 |
} break; |
||
365 |
60620 |
case LBM_TYPE_BYTE: |
|
366 |
✓✗ | 60620 |
if (f_b(fv, (uint8_t)lbm_dec_as_char(v))) { |
367 |
60620 |
return FLATTEN_VALUE_OK; |
|
368 |
} |
||
369 |
break; |
||
370 |
28 |
case LBM_TYPE_U: |
|
371 |
✓✗ | 28 |
if (f_u(fv, lbm_dec_u(v))) { |
372 |
28 |
return FLATTEN_VALUE_OK; |
|
373 |
} |
||
374 |
break; |
||
375 |
45374 |
case LBM_TYPE_I: |
|
376 |
✓✗ | 45374 |
if (f_i(fv, lbm_dec_i(v))) { |
377 |
45374 |
return FLATTEN_VALUE_OK; |
|
378 |
} |
||
379 |
break; |
||
380 |
31122 |
case LBM_TYPE_U32: |
|
381 |
✓✗ | 31122 |
if (f_u32(fv, lbm_dec_as_u32(v))) { |
382 |
31122 |
return FLATTEN_VALUE_OK; |
|
383 |
} |
||
384 |
break; |
||
385 |
29274 |
case LBM_TYPE_I32: |
|
386 |
✓✗ | 29274 |
if (f_i32(fv, lbm_dec_as_i32(v))) { |
387 |
29274 |
return FLATTEN_VALUE_OK; |
|
388 |
} |
||
389 |
break; |
||
390 |
28 |
case LBM_TYPE_U64: |
|
391 |
✓✗ | 28 |
if (f_u64(fv, lbm_dec_as_u64(v))) { |
392 |
28 |
return FLATTEN_VALUE_OK; |
|
393 |
} |
||
394 |
break; |
||
395 |
28 |
case LBM_TYPE_I64: |
|
396 |
✓✗ | 28 |
if (f_i64(fv, lbm_dec_as_i64(v))) { |
397 |
28 |
return FLATTEN_VALUE_OK; |
|
398 |
} |
||
399 |
break; |
||
400 |
56 |
case LBM_TYPE_FLOAT: |
|
401 |
✓✗ | 56 |
if (f_float(fv, lbm_dec_as_float(v))) { |
402 |
56 |
return FLATTEN_VALUE_OK; |
|
403 |
} |
||
404 |
break; |
||
405 |
28 |
case LBM_TYPE_DOUBLE: |
|
406 |
✓✗ | 28 |
if (f_double(fv, lbm_dec_as_double(v))) { |
407 |
28 |
return FLATTEN_VALUE_OK; |
|
408 |
} |
||
409 |
break; |
||
410 |
62972 |
case LBM_TYPE_SYMBOL: { |
|
411 |
62972 |
char *sym_str = (char*)lbm_get_name_by_symbol(lbm_dec_sym(v)); |
|
412 |
✓✗ | 62972 |
if (f_sym_string(fv, sym_str)) { |
413 |
62972 |
return FLATTEN_VALUE_OK; |
|
414 |
} |
||
415 |
} break; |
||
416 |
118692 |
case LBM_TYPE_ARRAY: { |
|
417 |
118692 |
lbm_int s = lbm_heap_array_get_size(v); |
|
418 |
118692 |
const uint8_t *d = lbm_heap_array_get_data_ro(v); |
|
419 |
✓✗✓✗ |
118692 |
if (s > 0 && d != NULL) { |
420 |
✓✗ | 118692 |
if (f_lbm_array(fv, (uint32_t)s, (uint8_t*)d)) { |
421 |
118692 |
return FLATTEN_VALUE_OK; |
|
422 |
} |
||
423 |
} else { |
||
424 |
return FLATTEN_VALUE_ERROR_ARRAY; |
||
425 |
} |
||
426 |
}break; |
||
427 |
default: |
||
428 |
return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED; |
||
429 |
} |
||
430 |
return FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL; |
||
431 |
} |
||
432 |
|||
433 |
56 |
lbm_value handle_flatten_error(int err_val) { |
|
434 |
✓✗✓✗ ✗ |
56 |
switch (err_val) { |
435 |
28 |
case FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED: |
|
436 |
28 |
return ENC_SYM_EERROR; |
|
437 |
case FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL: /* fall through */ |
||
438 |
case FLATTEN_VALUE_ERROR_FATAL: |
||
439 |
return ENC_SYM_FATAL_ERROR; |
||
440 |
28 |
case FLATTEN_VALUE_ERROR_CIRCULAR: /* fall through */ |
|
441 |
case FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH: |
||
442 |
28 |
return ENC_SYM_EERROR; |
|
443 |
case FLATTEN_VALUE_ERROR_ARRAY: /* fall through */ |
||
444 |
case FLATTEN_VALUE_ERROR_NOT_ENOUGH_MEMORY: |
||
445 |
return ENC_SYM_MERROR; |
||
446 |
} |
||
447 |
return ENC_SYM_NIL; |
||
448 |
} |
||
449 |
|||
450 |
34596 |
lbm_value flatten_value(lbm_value v) { |
|
451 |
|||
452 |
34596 |
lbm_value array_cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE); |
|
453 |
|||
454 |
✓✓ | 34596 |
if (array_cell == ENC_SYM_MERROR) { |
455 |
2 |
return array_cell; |
|
456 |
} |
||
457 |
|||
458 |
lbm_flat_value_t fv; |
||
459 |
|||
460 |
34594 |
lbm_array_header_t *array = NULL; |
|
461 |
34594 |
int required_mem = flatten_value_size(v, 0); |
|
462 |
✓✓ | 34594 |
if (required_mem > 0) { |
463 |
34538 |
array = (lbm_array_header_t *)lbm_malloc(sizeof(lbm_array_header_t)); |
|
464 |
✗✓ | 34538 |
if (array == NULL) { |
465 |
lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL); |
||
466 |
return ENC_SYM_MERROR; |
||
467 |
} |
||
468 |
|||
469 |
34538 |
bool r = lbm_start_flatten(&fv, (lbm_uint)required_mem); |
|
470 |
✗✓ | 34538 |
if (!r) { |
471 |
lbm_free(array); |
||
472 |
lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL); |
||
473 |
return ENC_SYM_MERROR; |
||
474 |
} |
||
475 |
|||
476 |
✓✗ | 34538 |
if (flatten_value_c(&fv, v) == FLATTEN_VALUE_OK) { |
477 |
// it would be wasteful to run finish_flatten here. |
||
478 |
34538 |
r = true; |
|
479 |
} else { |
||
480 |
r = false; |
||
481 |
} |
||
482 |
|||
483 |
✓✗ | 34538 |
if (r) { |
484 |
// lift flat_value |
||
485 |
34538 |
array->data = (lbm_uint*)fv.buf; |
|
486 |
34538 |
array->size = fv.buf_size; |
|
487 |
34538 |
lbm_set_car(array_cell, (lbm_uint)array); |
|
488 |
34538 |
array_cell = lbm_set_ptr_type(array_cell, LBM_TYPE_ARRAY); |
|
489 |
34538 |
return array_cell; |
|
490 |
} |
||
491 |
} |
||
492 |
56 |
lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL); |
|
493 |
56 |
return handle_flatten_error(required_mem); |
|
494 |
} |
||
495 |
|||
496 |
// ------------------------------------------------------------ |
||
497 |
// Unflattening |
||
498 |
61794 |
static bool extract_byte(lbm_flat_value_t *v, uint8_t *r) { |
|
499 |
✓✗ | 61794 |
if (v->buf_size >= v->buf_pos + 1) { |
500 |
61794 |
*r = v->buf[v->buf_pos++]; |
|
501 |
61794 |
return true; |
|
502 |
} |
||
503 |
return false; |
||
504 |
} |
||
505 |
|||
506 |
241339 |
static bool extract_word(lbm_flat_value_t *v, uint32_t *r) { |
|
507 |
241339 |
bool res = false; |
|
508 |
✓✗ | 241339 |
if (v->buf_size >= v->buf_pos + 4) { |
509 |
241339 |
uint32_t tmp = 0; |
|
510 |
241339 |
tmp |= (lbm_value)v->buf[v->buf_pos++]; |
|
511 |
241339 |
tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++]; |
|
512 |
241339 |
tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++]; |
|
513 |
241339 |
tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++]; |
|
514 |
241339 |
*r = tmp; |
|
515 |
241339 |
res = true; |
|
516 |
} |
||
517 |
241339 |
return res; |
|
518 |
} |
||
519 |
|||
520 |
84 |
static bool extract_dword(lbm_flat_value_t *v, uint64_t *r) { |
|
521 |
84 |
bool res = false; |
|
522 |
✓✗ | 84 |
if (v->buf_size >= v->buf_pos + 8) { |
523 |
84 |
uint64_t tmp = 0; |
|
524 |
84 |
tmp |= (lbm_value)v->buf[v->buf_pos++]; |
|
525 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
526 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
527 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
528 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
529 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
530 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
531 |
84 |
tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++]; |
|
532 |
84 |
*r = tmp; |
|
533 |
84 |
res = true;; |
|
534 |
} |
||
535 |
84 |
return res; |
|
536 |
} |
||
537 |
|||
538 |
/* Recursive and potentially stack hungry for large flat values */ |
||
539 |
690831 |
static int lbm_unflatten_value_internal(lbm_flat_value_t *v, lbm_value *res) { |
|
540 |
✗✓ | 690831 |
if (v->buf_size == v->buf_pos) return UNFLATTEN_MALFORMED; |
541 |
|||
542 |
690831 |
uint8_t curr = v->buf[v->buf_pos++]; |
|
543 |
|||
544 |
✓✓✓✓ ✓✓✗✗ ✓✓✓✓ ✓✓✓✓ ✗ |
690831 |
switch(curr) { |
545 |
324092 |
case S_CONS: { |
|
546 |
lbm_value a; |
||
547 |
lbm_value b; |
||
548 |
324092 |
int r = lbm_unflatten_value_internal(v, &a); |
|
549 |
✓✓ | 324092 |
if (r == UNFLATTEN_OK) { |
550 |
323682 |
r = lbm_unflatten_value_internal(v, &b); |
|
551 |
✓✓ | 323682 |
if (r == UNFLATTEN_OK) { |
552 |
lbm_value c; |
||
553 |
320476 |
c = lbm_cons(a,b); |
|
554 |
✓✓ | 320476 |
if (lbm_is_symbol_merror(c)) return UNFLATTEN_GC_RETRY; |
555 |
320234 |
*res = c; |
|
556 |
320234 |
r = UNFLATTEN_OK; |
|
557 |
} |
||
558 |
} |
||
559 |
323850 |
return r; |
|
560 |
} |
||
561 |
84 |
case S_LBM_LISP_ARRAY: { |
|
562 |
uint32_t size; |
||
563 |
84 |
bool b = extract_word(v, &size); |
|
564 |
84 |
int r = UNFLATTEN_MALFORMED; |
|
565 |
✓✗ | 84 |
if (b) { |
566 |
lbm_value array; |
||
567 |
84 |
lbm_heap_allocate_lisp_array(&array, size); |
|
568 |
84 |
lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(array); |
|
569 |
84 |
lbm_value *arrdata = (lbm_value*)header->data; |
|
570 |
✗✓ | 84 |
if (lbm_is_symbol_merror(array)) return UNFLATTEN_GC_RETRY; |
571 |
lbm_value a; |
||
572 |
✓✓ | 336 |
for (uint32_t i = 0; i < size; i ++) { |
573 |
252 |
r = lbm_unflatten_value_internal(v, &a); |
|
574 |
✓✗ | 252 |
if (r == UNFLATTEN_OK) { |
575 |
252 |
arrdata[i] = a; |
|
576 |
} else { |
||
577 |
break; |
||
578 |
} |
||
579 |
} |
||
580 |
84 |
*res = array; |
|
581 |
} |
||
582 |
84 |
return r; |
|
583 |
} |
||
584 |
5889 |
case S_SYM_VALUE: { |
|
585 |
lbm_uint tmp; |
||
586 |
bool b; |
||
587 |
#ifndef LBM64 |
||
588 |
5889 |
b = extract_word(v, &tmp); |
|
589 |
#else |
||
590 |
b = extract_dword(v, &tmp); |
||
591 |
#endif |
||
592 |
✓✗ | 5889 |
if (b) { |
593 |
5889 |
*res = lbm_enc_sym(tmp); |
|
594 |
5889 |
return UNFLATTEN_OK; |
|
595 |
} |
||
596 |
return UNFLATTEN_MALFORMED; |
||
597 |
} |
||
598 |
61794 |
case S_BYTE_VALUE: { |
|
599 |
uint8_t tmp; |
||
600 |
61794 |
bool b = extract_byte(v, &tmp); |
|
601 |
✓✗ | 61794 |
if (b) { |
602 |
61794 |
*res = lbm_enc_char((uint8_t)tmp); |
|
603 |
61794 |
return UNFLATTEN_OK; |
|
604 |
} |
||
605 |
return UNFLATTEN_MALFORMED; |
||
606 |
} |
||
607 |
45668 |
case S_I28_VALUE: { |
|
608 |
uint32_t tmp; |
||
609 |
bool b; |
||
610 |
45668 |
b = extract_word(v, &tmp); |
|
611 |
✓✗ | 45668 |
if (b) { |
612 |
45668 |
*res = lbm_enc_i((int32_t)tmp); |
|
613 |
45668 |
return UNFLATTEN_OK; |
|
614 |
} |
||
615 |
return UNFLATTEN_MALFORMED; |
||
616 |
} |
||
617 |
28 |
case S_U28_VALUE: { |
|
618 |
uint32_t tmp; |
||
619 |
bool b; |
||
620 |
28 |
b = extract_word(v, &tmp); |
|
621 |
✓✗ | 28 |
if (b) { |
622 |
28 |
*res = lbm_enc_u((uint32_t)tmp); |
|
623 |
28 |
return UNFLATTEN_OK; |
|
624 |
} |
||
625 |
return UNFLATTEN_MALFORMED; |
||
626 |
} |
||
627 |
case S_I56_VALUE: { |
||
628 |
uint64_t tmp; |
||
629 |
bool b; |
||
630 |
b = extract_dword(v, &tmp); |
||
631 |
if (b) { |
||
632 |
#ifndef LBM64 |
||
633 |
*res = lbm_enc_i64((int64_t)tmp); |
||
634 |
#else |
||
635 |
*res = lbm_enc_i((int64_t)tmp); |
||
636 |
#endif |
||
637 |
return UNFLATTEN_OK; |
||
638 |
} |
||
639 |
return UNFLATTEN_MALFORMED; |
||
640 |
} |
||
641 |
case S_U56_VALUE: { |
||
642 |
uint64_t tmp; |
||
643 |
bool b; |
||
644 |
b = extract_dword(v, &tmp); |
||
645 |
if (b) { |
||
646 |
#ifndef LBM64 |
||
647 |
*res = lbm_enc_u64(tmp); |
||
648 |
#else |
||
649 |
*res = lbm_enc_u(tmp); |
||
650 |
#endif |
||
651 |
return UNFLATTEN_OK; |
||
652 |
} |
||
653 |
return UNFLATTEN_MALFORMED; |
||
654 |
} |
||
655 |
7634 |
case S_FLOAT_VALUE: { |
|
656 |
uint32_t tmp; |
||
657 |
bool b; |
||
658 |
7634 |
b = extract_word(v, &tmp); |
|
659 |
✓✗ | 7634 |
if (b) { |
660 |
lbm_float f; |
||
661 |
7634 |
memcpy(&f, &tmp, sizeof(lbm_float)); |
|
662 |
7634 |
lbm_value im = lbm_enc_float(f); |
|
663 |
✗✓ | 7634 |
if (lbm_is_symbol_merror(im)) { |
664 |
return UNFLATTEN_GC_RETRY; |
||
665 |
} |
||
666 |
7634 |
*res = im; |
|
667 |
7634 |
return UNFLATTEN_OK; |
|
668 |
} |
||
669 |
return UNFLATTEN_MALFORMED; |
||
670 |
} |
||
671 |
28 |
case S_DOUBLE_VALUE: { |
|
672 |
uint64_t tmp; |
||
673 |
bool b; |
||
674 |
28 |
b = extract_dword(v, &tmp); |
|
675 |
✓✗ | 28 |
if (b) { |
676 |
double f; |
||
677 |
28 |
memcpy(&f, &tmp, sizeof(uint64_t)); |
|
678 |
28 |
lbm_value im = lbm_enc_double(f); |
|
679 |
✗✓ | 28 |
if (lbm_is_symbol_merror(im)) { |
680 |
return UNFLATTEN_GC_RETRY; |
||
681 |
} |
||
682 |
28 |
*res = im; |
|
683 |
28 |
return UNFLATTEN_OK; |
|
684 |
} |
||
685 |
return UNFLATTEN_MALFORMED; |
||
686 |
} |
||
687 |
29562 |
case S_I32_VALUE: { |
|
688 |
uint32_t tmp; |
||
689 |
✓✗ | 29562 |
if (extract_word(v, &tmp)) { |
690 |
29562 |
lbm_value im = lbm_enc_i32((int32_t)tmp); |
|
691 |
✓✓ | 29562 |
if (lbm_is_symbol_merror(im)) { |
692 |
36 |
return UNFLATTEN_GC_RETRY; |
|
693 |
} |
||
694 |
29526 |
*res = im; |
|
695 |
29526 |
return UNFLATTEN_OK; |
|
696 |
} |
||
697 |
return UNFLATTEN_MALFORMED; |
||
698 |
} |
||
699 |
31766 |
case S_U32_VALUE: { |
|
700 |
uint32_t tmp; |
||
701 |
✓✗ | 31766 |
if (extract_word(v, &tmp)) { |
702 |
31766 |
lbm_value im = lbm_enc_u32(tmp); |
|
703 |
✓✓ | 31766 |
if (lbm_is_symbol_merror(im)) { |
704 |
14 |
return UNFLATTEN_GC_RETRY; |
|
705 |
} |
||
706 |
31752 |
*res = im; |
|
707 |
31752 |
return UNFLATTEN_OK; |
|
708 |
} |
||
709 |
return UNFLATTEN_MALFORMED; |
||
710 |
} |
||
711 |
28 |
case S_I64_VALUE: { |
|
712 |
28 |
uint64_t tmp = 0; |
|
713 |
✓✗ | 28 |
if (extract_dword(v, &tmp)) { |
714 |
28 |
lbm_value im = lbm_enc_i64((int64_t)tmp); |
|
715 |
✗✓ | 28 |
if (lbm_is_symbol_merror(im)) { |
716 |
return UNFLATTEN_GC_RETRY; |
||
717 |
} |
||
718 |
28 |
*res = im; |
|
719 |
28 |
return UNFLATTEN_OK; |
|
720 |
} |
||
721 |
return UNFLATTEN_MALFORMED; |
||
722 |
} |
||
723 |
28 |
case S_U64_VALUE: { |
|
724 |
28 |
uint64_t tmp = 0; |
|
725 |
✓✗ | 28 |
if (extract_dword(v, &tmp)) { |
726 |
28 |
lbm_value im = lbm_enc_u64(tmp); |
|
727 |
✗✓ | 28 |
if (lbm_is_symbol_merror(im)) { |
728 |
return UNFLATTEN_GC_RETRY; |
||
729 |
} |
||
730 |
28 |
*res = im; |
|
731 |
28 |
return UNFLATTEN_OK; |
|
732 |
} |
||
733 |
return UNFLATTEN_MALFORMED; |
||
734 |
} |
||
735 |
120708 |
case S_LBM_ARRAY: { |
|
736 |
uint32_t num_elt; |
||
737 |
✓✗ | 120708 |
if (extract_word(v, &num_elt)) { |
738 |
✓✓ | 120708 |
if (lbm_heap_allocate_array(res, num_elt)) { |
739 |
120348 |
lbm_array_header_t *arr = (lbm_array_header_t*)lbm_car(*res); |
|
740 |
120348 |
lbm_uint num_bytes = num_elt; |
|
741 |
120348 |
memcpy(arr->data, v->buf + v->buf_pos, num_bytes); |
|
742 |
120348 |
v->buf_pos += num_bytes; |
|
743 |
} else { |
||
744 |
360 |
return UNFLATTEN_GC_RETRY; |
|
745 |
} |
||
746 |
120348 |
return UNFLATTEN_OK; |
|
747 |
} |
||
748 |
return UNFLATTEN_MALFORMED; |
||
749 |
} |
||
750 |
63522 |
case S_SYM_STRING: { |
|
751 |
lbm_uint sym_id; |
||
752 |
✓✗ | 63522 |
if (lbm_add_symbol((char *)(v->buf + v->buf_pos), &sym_id)) { |
753 |
63522 |
lbm_uint num_bytes = strlen((char*)(v->buf + v->buf_pos)) + 1; |
|
754 |
63522 |
v->buf_pos += num_bytes; |
|
755 |
63522 |
*res = lbm_enc_sym(sym_id); |
|
756 |
63522 |
return UNFLATTEN_OK; |
|
757 |
} |
||
758 |
return UNFLATTEN_GC_RETRY; |
||
759 |
} |
||
760 |
default: |
||
761 |
return UNFLATTEN_MALFORMED; |
||
762 |
} |
||
763 |
} |
||
764 |
|||
765 |
42153 |
bool lbm_unflatten_value(lbm_flat_value_t *v, lbm_value *res) { |
|
766 |
42153 |
bool b = false; |
|
767 |
#ifdef LBM_ALWAYS_GC |
||
768 |
lbm_perform_gc(); |
||
769 |
#endif |
||
770 |
42153 |
int r = lbm_unflatten_value_internal(v,res); |
|
771 |
✓✓ | 42153 |
if (r == UNFLATTEN_GC_RETRY) { |
772 |
652 |
lbm_perform_gc(); |
|
773 |
652 |
v->buf_pos = 0; |
|
774 |
652 |
r = lbm_unflatten_value_internal(v,res); |
|
775 |
} |
||
776 |
✗✓ | 42153 |
if (r == UNFLATTEN_MALFORMED) { |
777 |
*res = ENC_SYM_EERROR; |
||
778 |
✗✓ | 42153 |
} else if (r == UNFLATTEN_GC_RETRY) { |
779 |
*res = ENC_SYM_MERROR; |
||
780 |
} else { |
||
781 |
42153 |
b = true; |
|
782 |
} |
||
783 |
// Do not free the flat value buffer here. |
||
784 |
// there are 2 cases: |
||
785 |
// 1: unflatten was called from lisp code -> GC removes the buffer. |
||
786 |
// 2: unflatten called from event processing -> event processor frees buffer. |
||
787 |
42153 |
return b; |
|
788 |
} |
Generated by: GCOVR (Version 4.2) |