GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/lbm_flat_value.c
Date: 2024-11-05 17:11:09
Exec Total Coverage
Lines: 421 488 86.3%
Functions: 33 33 100.0%
Branches: 186 311 59.8%

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