GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/lbm_flat_value.c
Date: 2024-08-06 17:32:21
Exec Total Coverage
Lines: 272 479 56.8%
Functions: 21 32 65.6%
Branches: 132 325 40.6%

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