GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/lbm_flat_value.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 513 607 84.5%
Functions: 35 36 97.2%
Branches: 240 397 60.5%

Line Branch Exec Source
1 /*
2 Copyright 2023, 2024, 2025 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 84406 bool lbm_start_flatten(lbm_flat_value_t *v, size_t buffer_size) {
33 84406 bool res = false;
34 84406 uint8_t *data = lbm_malloc_reserve(buffer_size);
35
1/2
✓ Branch 0 taken 84406 times.
✗ Branch 1 not taken.
84406 if (data) {
36 84406 v->buf = data;
37 84406 v->buf_size = buffer_size;
38 84406 v->buf_pos = 0;
39 84406 res = true;
40 }
41 84406 return res;
42 }
43
44 15273 bool lbm_finish_flatten(lbm_flat_value_t *v) {
45 lbm_uint size_words;
46
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15271 times.
15273 if (v->buf_pos % sizeof(lbm_uint) == 0) {
47 2 size_words = v->buf_pos / sizeof(lbm_uint);
48 } else {
49 15271 size_words = (v->buf_pos / sizeof(lbm_uint)) + 1;
50 }
51
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 15217 times.
15273 if (v->buf_size <= size_words * sizeof(lbm_uint)) return true;
52 15217 v->buf_size = size_words * sizeof(lbm_uint);
53 15217 return (lbm_memory_shrink((lbm_uint*)v->buf, size_words) >= 0);
54 }
55
56 845836 static bool write_byte(lbm_flat_value_t *v, uint8_t b) {
57 845836 bool res = false;
58
1/2
✓ Branch 0 taken 845836 times.
✗ Branch 1 not taken.
845836 if (v->buf_size >= v->buf_pos + 1) {
59 845836 v->buf[v->buf_pos++] = b;
60 845836 res = true;
61 }
62 845836 return res;
63 }
64
65 363721 static bool write_bytes(lbm_flat_value_t *v, uint8_t *data,lbm_uint num_bytes) {
66 363721 bool res = false;
67
1/2
✓ Branch 0 taken 363721 times.
✗ Branch 1 not taken.
363721 if (v->buf_size >= v->buf_pos + num_bytes) {
68 363721 memcpy(v->buf + v->buf_pos, data, num_bytes);
69 363721 v->buf_pos += num_bytes;
70 363721 res = true;
71 }
72 363721 return res;
73 }
74
75 424594 static bool write_word(lbm_flat_value_t *v, uint32_t w) {
76 424594 bool res = false;
77
1/2
✓ Branch 0 taken 424594 times.
✗ Branch 1 not taken.
424594 if (v->buf_size >= v->buf_pos + 4) {
78 424594 v->buf[v->buf_pos++] = (uint8_t)(w >> 24);
79 424594 v->buf[v->buf_pos++] = (uint8_t)(w >> 16);
80 424594 v->buf[v->buf_pos++] = (uint8_t)(w >> 8);
81 424594 v->buf[v->buf_pos++] = (uint8_t)w;
82 424594 res = true;
83 }
84 424594 return res;
85 }
86
87 52425 static bool write_dword(lbm_flat_value_t *v, uint64_t w) {
88 52425 bool res = false;
89
1/2
✓ Branch 0 taken 52425 times.
✗ Branch 1 not taken.
52425 if (v->buf_size >= v->buf_pos + 8) {
90 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 56);
91 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 48);
92 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 40);
93 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 32);
94 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 24);
95 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 16);
96 52425 v->buf[v->buf_pos++] = (uint8_t)(w >> 8);
97 52425 v->buf[v->buf_pos++] = (uint8_t)w;
98 52425 res = true;
99 }
100 52425 return res;
101 }
102
103 639408 bool f_cons(lbm_flat_value_t *v) {
104 639408 bool res = false;
105
1/2
✓ Branch 0 taken 639408 times.
✗ Branch 1 not taken.
639408 if (v->buf_size >= v->buf_pos + 1) {
106 639408 v->buf[v->buf_pos++] = S_CONS;
107 639408 res = true;
108 }
109 639408 return res;
110 }
111
112 224 bool f_lisp_array(lbm_flat_value_t *v, uint32_t size) {
113 // arrays are smaller than 2^32 elements long
114 224 bool res = true;
115
2/4
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 224 times.
✗ Branch 3 not taken.
224 res = res && write_byte(v, S_LBM_LISP_ARRAY);
116
2/4
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 224 times.
✗ Branch 3 not taken.
224 res = res && write_word(v, size); // number of elements.
117 224 return res;
118 }
119
120 11633 bool f_sym(lbm_flat_value_t *v, lbm_uint sym_id) {
121 11633 bool res = true;
122
2/4
✓ Branch 0 taken 11633 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11633 times.
✗ Branch 3 not taken.
11633 res = res && write_byte(v,S_SYM_VALUE);
123 #ifndef LBM64
124
2/4
✓ Branch 0 taken 5030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5030 times.
✗ Branch 3 not taken.
5030 res = res && write_word(v,sym_id);
125 #else
126
2/4
✓ Branch 0 taken 6603 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6603 times.
✗ Branch 3 not taken.
6603 res = res && write_dword(v,sym_id);
127 #endif
128 11633 return res;
129 }
130
131 126225 bool f_sym_string(lbm_flat_value_t *v, char *str) {
132 126225 bool res = false;
133
1/2
✓ Branch 0 taken 126225 times.
✗ Branch 1 not taken.
126225 if (str) {
134 126225 lbm_uint sym_bytes = strlen(str) + 1;
135
2/4
✓ Branch 0 taken 126225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126225 times.
✗ Branch 3 not taken.
252450 if (write_byte(v, S_SYM_STRING) &&
136 126225 write_bytes(v, (uint8_t*)str, sym_bytes)) {
137 126225 res = true;
138 }
139 }
140 126225 return res;
141 }
142
143 // Potentially a difference between 32/64 bit version.
144 // strlen returns size_t which is different on 32/64 bit platforms.
145 126145 int f_sym_string_bytes(lbm_value sym) {
146 126145 int res = FLATTEN_VALUE_ERROR_FATAL;
147
1/2
✓ Branch 0 taken 126145 times.
✗ Branch 1 not taken.
126145 if (lbm_is_symbol(sym)) {
148 126145 lbm_uint s = lbm_dec_sym(sym);
149 126145 char *sym_str = (char*)lbm_get_name_by_symbol(s);
150
1/2
✓ Branch 0 taken 126145 times.
✗ Branch 1 not taken.
126145 if (sym_str) {
151 126145 lbm_uint sym_bytes = strlen(sym_str) + 1;
152 126145 res = (int)sym_bytes;
153 }
154 }
155 126145 return res;
156 }
157
158 91252 bool f_i(lbm_flat_value_t *v, lbm_int i) {
159 91252 bool res = true;
160 #ifndef LBM64
161
2/4
✓ Branch 0 taken 45626 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45626 times.
✗ Branch 3 not taken.
45626 res = res && write_byte(v,S_I28_VALUE);
162
2/4
✓ Branch 0 taken 45626 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45626 times.
✗ Branch 3 not taken.
45626 res = res && write_word(v,(uint32_t)i);
163 #else
164
2/4
✓ Branch 0 taken 45626 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45626 times.
✗ Branch 3 not taken.
45626 res = res && write_byte(v,S_I56_VALUE);
165
2/4
✓ Branch 0 taken 45626 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45626 times.
✗ Branch 3 not taken.
45626 res = res && write_dword(v, (uint64_t)i);
166 #endif
167 91252 return res;
168 }
169
170 56 bool f_u(lbm_flat_value_t *v, lbm_uint u) {
171 56 bool res = true;
172 #ifndef LBM64
173
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 res = res && write_byte(v,S_U28_VALUE);
174
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 res = res && write_word(v,(uint32_t)u);
175 #else
176
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 res = res && write_byte(v,S_U56_VALUE);
177
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 res = res && write_dword(v,(uint64_t)u);
178 #endif
179 56 return res;
180 }
181
182 121296 bool f_b(lbm_flat_value_t *v, uint8_t b) {
183 121296 bool res = true;
184
2/4
✓ Branch 0 taken 121296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121296 times.
✗ Branch 3 not taken.
121296 res = res && write_byte(v,S_BYTE_VALUE);
185
2/4
✓ Branch 0 taken 121296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121296 times.
✗ Branch 3 not taken.
121296 res = res && write_byte(v,b);
186 121296 return res;
187 }
188
189 58548 bool f_i32(lbm_flat_value_t *v, int32_t w) {
190 58548 bool res = true;
191
2/4
✓ Branch 0 taken 58548 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58548 times.
✗ Branch 3 not taken.
58548 res = res && write_byte(v, S_I32_VALUE);
192
2/4
✓ Branch 0 taken 58548 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58548 times.
✗ Branch 3 not taken.
58548 res = res && write_word(v, (uint32_t)w);
193 58548 return res;
194 }
195
196 62244 bool f_u32(lbm_flat_value_t *v, uint32_t w) {
197 62244 bool res = true;
198
2/4
✓ Branch 0 taken 62244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62244 times.
✗ Branch 3 not taken.
62244 res = res && write_byte(v, S_U32_VALUE);
199
2/4
✓ Branch 0 taken 62244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62244 times.
✗ Branch 3 not taken.
62244 res = res && write_word(v, w);
200 62244 return res;
201 }
202
203 15398 bool f_float(lbm_flat_value_t *v, float f) {
204 15398 bool res = true;
205
2/4
✓ Branch 0 taken 15398 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15398 times.
✗ Branch 3 not taken.
15398 res = res && write_byte(v, S_FLOAT_VALUE);
206 uint32_t u;
207 15398 memcpy(&u, &f, sizeof(uint32_t));
208
2/4
✓ Branch 0 taken 15398 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15398 times.
✗ Branch 3 not taken.
15398 res = res && write_word(v, (uint32_t)u);
209 15398 return res;
210 }
211
212 56 bool f_double(lbm_flat_value_t *v, double d) {
213 56 bool res = true;
214
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 res = res && write_byte(v, S_DOUBLE_VALUE);
215 uint64_t u;
216 56 memcpy(&u, &d, sizeof(uint64_t));
217
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 res = res && write_dword(v, u);
218 56 return res;
219 }
220
221 56 bool f_i64(lbm_flat_value_t *v, int64_t w) {
222 56 bool res = true;
223
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 res = res && write_byte(v, S_I64_VALUE);
224
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 res = res && write_dword(v, (uint64_t)w);
225 56 return res;
226 }
227
228 56 bool f_u64(lbm_flat_value_t *v, uint64_t w) {
229 56 bool res = true;
230
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 res = res && write_byte(v, S_U64_VALUE);
231
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 res = res && write_dword(v, w);
232 56 return res;
233 }
234
235 // num_bytes is specifically an uint32_t
236 237496 bool f_lbm_array(lbm_flat_value_t *v, uint32_t num_bytes, uint8_t *data) {
237 237496 bool res = write_byte(v, S_LBM_ARRAY);
238
2/4
✓ Branch 0 taken 237496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 237496 times.
✗ Branch 3 not taken.
237496 res = res && write_word(v, num_bytes);
239
2/4
✓ Branch 0 taken 237496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 237496 times.
✗ Branch 3 not taken.
237496 res = res && write_bytes(v, data, num_bytes);
240 237496 return res;
241 }
242
243 static int flatten_maximum_depth = FLATTEN_VALUE_MAXIMUM_DEPTH;
244
245 56 void lbm_set_max_flatten_depth(int depth) {
246 56 flatten_maximum_depth = depth;
247 56 }
248
249 int lbm_get_max_flatten_depth(void) {
250 return flatten_maximum_depth;
251 }
252
253 56 void flatten_error(jmp_buf jb, int val) {
254 56 longjmp(jb, val);
255 }
256
257 1325493 int flatten_value_size_internal(jmp_buf jb, lbm_value v, int depth, bool image) {
258
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 1325437 times.
1325493 if (depth > flatten_maximum_depth) {
259 56 flatten_error(jb, FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH);
260 }
261
262 1325437 lbm_uint t = lbm_type_of(v);
263
3/4
✓ Branch 0 taken 926172 times.
✓ Branch 1 taken 399265 times.
✓ Branch 2 taken 926172 times.
✗ Branch 3 not taken.
1325437 if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) {
264 // Clear constant bit, it is irrelevant to flattening
265 926172 t = t & ~(LBM_PTR_TO_CONSTANT_BIT);
266 }
267
268
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1325437 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1325437 if (image && lbm_is_ptr(v) && (v & LBM_PTR_TO_CONSTANT_BIT)) {
269 // If flattening to image, constants can be stored by reference.
270 return (sizeof(lbm_uint) + 1); // one byte tag, one word ptr
271 }
272
273
8/9
✓ Branch 0 taken 627864 times.
✓ Branch 1 taken 224 times.
✓ Branch 2 taken 121328 times.
✓ Branch 3 taken 91324 times.
✓ Branch 4 taken 120936 times.
✓ Branch 5 taken 168 times.
✓ Branch 6 taken 126145 times.
✓ Branch 7 taken 237448 times.
✗ Branch 8 not taken.
1325437 switch (t) {
274 627864 case LBM_TYPE_CONS: {
275 627864 int res = 0;
276 627864 int s1 = flatten_value_size_internal(jb,lbm_car(v), depth + 1, image);
277
1/2
✓ Branch 0 taken 627696 times.
✗ Branch 1 not taken.
627696 if (s1 > 0) {
278 627696 int s2 = flatten_value_size_internal(jb,lbm_cdr(v), depth + 1, image);
279
1/2
✓ Branch 0 taken 627696 times.
✗ Branch 1 not taken.
627696 if (s2 > 0) {
280 627696 res = (1 + s1 + s2);
281 }
282 }
283 627696 return res;
284 }
285 224 case LBM_TYPE_LISPARRAY: {
286 224 int sum = 4 + 1; // sizeof(uint32_t) + 1;
287 224 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(v);
288
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 if (header) {
289 224 lbm_value *arrdata = (lbm_value*)header->data;
290 224 lbm_uint size = header->size / sizeof(lbm_value);
291
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 224 times.
952 for (lbm_uint i = 0; i < size; i ++ ) {
292 728 sum += flatten_value_size_internal(jb, arrdata[i], depth + 1, image);
293 }
294 } else {
295 flatten_error(jb, FLATTEN_VALUE_ERROR_ARRAY);
296 }
297 224 return sum;
298 }
299 121328 case LBM_TYPE_BYTE:
300 121328 return 1 + 1;
301 91324 case LBM_TYPE_U: /* fall through */
302 case LBM_TYPE_I:
303 #ifndef LBM64
304 45662 return 1 + 4;
305 #else
306 45662 return 1 + 8;
307 #endif
308 120936 case LBM_TYPE_U32: /* fall through */
309 case LBM_TYPE_I32:
310 case LBM_TYPE_FLOAT:
311 120936 return 1 + 4;
312 168 case LBM_TYPE_U64: /* fall through */
313 case LBM_TYPE_I64:
314 case LBM_TYPE_DOUBLE:
315 168 return 1 + 8;
316 126145 case LBM_TYPE_SYMBOL: {
317
1/2
✓ Branch 0 taken 126145 times.
✗ Branch 1 not taken.
126145 if (!image) {
318 126145 int s = f_sym_string_bytes(v);
319
1/2
✓ Branch 0 taken 126145 times.
✗ Branch 1 not taken.
126145 if (s > 0) return 1 + s;
320 flatten_error(jb, (int)s);
321 } else {
322 return 1 + sizeof(lbm_uint);
323 }
324 } return 0; // already terminated with error
325 237448 case LBM_TYPE_ARRAY: {
326 // Platform dependent size.
327 // TODO: Something needs to be done to these inconsistencies.
328 237448 lbm_int s = lbm_heap_array_get_size(v);
329
1/2
✓ Branch 0 taken 237448 times.
✗ Branch 1 not taken.
237448 if (s > 0)
330 237448 return 1 + 4 + (int)s;
331 flatten_error(jb, (int)s);
332 } return 0; // already terminated with error
333 default:
334 return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED;
335 }
336 }
337
338 69205 int flatten_value_size(lbm_value v, bool image) {
339 jmp_buf jb;
340 69205 int r = setjmp(jb);
341
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 69205 times.
69261 if (r != 0) {
342 56 return r;
343 }
344 69205 return flatten_value_size_internal(jb, v, 0, image);
345 }
346
347 1324933 int flatten_value_c(lbm_flat_value_t *fv, lbm_value v) {
348
349 1324933 lbm_uint t = lbm_type_of(v);
350
3/4
✓ Branch 0 taken 925764 times.
✓ Branch 1 taken 399169 times.
✓ Branch 2 taken 925764 times.
✗ Branch 3 not taken.
1324933 if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) {
351 // Clear constant bit, it is irrelevant to flattening
352 925764 t = t & ~(LBM_PTR_TO_CONSTANT_BIT);
353 }
354
355
13/14
✓ Branch 0 taken 627536 times.
✓ Branch 1 taken 224 times.
✓ Branch 2 taken 121296 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 91252 times.
✓ Branch 5 taken 62244 times.
✓ Branch 6 taken 58548 times.
✓ Branch 7 taken 56 times.
✓ Branch 8 taken 56 times.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 56 times.
✓ Branch 11 taken 126113 times.
✓ Branch 12 taken 237384 times.
✗ Branch 13 not taken.
1324933 switch (t) {
356 627536 case LBM_TYPE_CONS: {
357 627536 bool res = true;
358
2/4
✓ Branch 0 taken 627536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 627536 times.
✗ Branch 3 not taken.
627536 res = res && f_cons(fv);
359
1/2
✓ Branch 0 taken 627536 times.
✗ Branch 1 not taken.
627536 if (res) {
360 627536 int fv_r = flatten_value_c(fv, lbm_car(v));
361
1/2
✓ Branch 0 taken 627536 times.
✗ Branch 1 not taken.
627536 if (fv_r == FLATTEN_VALUE_OK) {
362 627536 fv_r = flatten_value_c(fv, lbm_cdr(v));
363 }
364 627536 return fv_r;
365 }
366 }break;
367 224 case LBM_TYPE_LISPARRAY: {
368 224 lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(v);
369
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 if (header) {
370 224 lbm_value *arrdata = (lbm_value*)header->data;
371 // always exact multiple of sizeof(lbm_value)
372 224 uint32_t size = (uint32_t)(header->size / sizeof(lbm_value));
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
224 if (!f_lisp_array(fv, size)) return FLATTEN_VALUE_ERROR_NOT_ENOUGH_MEMORY;
374 224 int fv_r = FLATTEN_VALUE_OK;
375
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 224 times.
952 for (lbm_uint i = 0; i < size; i ++ ) {
376 728 fv_r = flatten_value_c(fv, arrdata[i]);
377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 728 times.
728 if (fv_r != FLATTEN_VALUE_OK) {
378 break;
379 }
380 }
381 224 return fv_r;
382 } else {
383 return FLATTEN_VALUE_ERROR_ARRAY;
384 }
385 } break;
386 121296 case LBM_TYPE_BYTE:
387
1/2
✓ Branch 0 taken 121296 times.
✗ Branch 1 not taken.
121296 if (f_b(fv, (uint8_t)lbm_dec_as_char(v))) {
388 121296 return FLATTEN_VALUE_OK;
389 }
390 break;
391 56 case LBM_TYPE_U:
392
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (f_u(fv, lbm_dec_u(v))) {
393 56 return FLATTEN_VALUE_OK;
394 }
395 break;
396 91252 case LBM_TYPE_I:
397
1/2
✓ Branch 0 taken 91252 times.
✗ Branch 1 not taken.
91252 if (f_i(fv, lbm_dec_i(v))) {
398 91252 return FLATTEN_VALUE_OK;
399 }
400 break;
401 62244 case LBM_TYPE_U32:
402
1/2
✓ Branch 0 taken 62244 times.
✗ Branch 1 not taken.
62244 if (f_u32(fv, lbm_dec_as_u32(v))) {
403 62244 return FLATTEN_VALUE_OK;
404 }
405 break;
406 58548 case LBM_TYPE_I32:
407
1/2
✓ Branch 0 taken 58548 times.
✗ Branch 1 not taken.
58548 if (f_i32(fv, lbm_dec_as_i32(v))) {
408 58548 return FLATTEN_VALUE_OK;
409 }
410 break;
411 56 case LBM_TYPE_U64:
412
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (f_u64(fv, lbm_dec_as_u64(v))) {
413 56 return FLATTEN_VALUE_OK;
414 }
415 break;
416 56 case LBM_TYPE_I64:
417
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (f_i64(fv, lbm_dec_as_i64(v))) {
418 56 return FLATTEN_VALUE_OK;
419 }
420 break;
421 112 case LBM_TYPE_FLOAT:
422
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (f_float(fv, lbm_dec_as_float(v))) {
423 112 return FLATTEN_VALUE_OK;
424 }
425 break;
426 56 case LBM_TYPE_DOUBLE:
427
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (f_double(fv, lbm_dec_as_double(v))) {
428 56 return FLATTEN_VALUE_OK;
429 }
430 break;
431 126113 case LBM_TYPE_SYMBOL: {
432 126113 char *sym_str = (char*)lbm_get_name_by_symbol(lbm_dec_sym(v));
433
1/2
✓ Branch 0 taken 126113 times.
✗ Branch 1 not taken.
126113 if (f_sym_string(fv, sym_str)) {
434 126113 return FLATTEN_VALUE_OK;
435 }
436 } break;
437 237384 case LBM_TYPE_ARRAY: {
438 237384 lbm_int s = lbm_heap_array_get_size(v);
439 237384 const uint8_t *d = lbm_heap_array_get_data_ro(v);
440
2/4
✓ Branch 0 taken 237384 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 237384 times.
✗ Branch 3 not taken.
237384 if (s > 0 && d != NULL) {
441
1/2
✓ Branch 0 taken 237384 times.
✗ Branch 1 not taken.
237384 if (f_lbm_array(fv, (uint32_t)s, (uint8_t*)d)) {
442 237384 return FLATTEN_VALUE_OK;
443 }
444 } else {
445 return FLATTEN_VALUE_ERROR_ARRAY;
446 }
447 }break;
448 default:
449 return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED;
450 }
451 return FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL;
452 }
453
454 56 lbm_value handle_flatten_error(int err_val) {
455
1/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
56 switch (err_val) {
456 case FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED:
457 return ENC_SYM_EERROR;
458 case FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL: /* fall through */
459 case FLATTEN_VALUE_ERROR_FATAL:
460 return ENC_SYM_FATAL_ERROR;
461 56 case FLATTEN_VALUE_ERROR_CIRCULAR: /* fall through */
462 case FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH:
463 56 return ENC_SYM_EERROR;
464 case FLATTEN_VALUE_ERROR_ARRAY: /* fall through */
465 case FLATTEN_VALUE_ERROR_NOT_ENOUGH_MEMORY:
466 return ENC_SYM_MERROR;
467 }
468 return ENC_SYM_NIL;
469 }
470
471 69221 lbm_value flatten_value(lbm_value v) {
472
473 69221 lbm_value array_cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE);
474
475
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 69205 times.
69221 if (array_cell == ENC_SYM_MERROR) {
476 16 return array_cell;
477 }
478
479 lbm_flat_value_t fv;
480
481 69205 lbm_array_header_t *array = NULL;
482 69205 int required_mem = flatten_value_size(v, false);
483
2/2
✓ Branch 0 taken 69149 times.
✓ Branch 1 taken 56 times.
69205 if (required_mem > 0) {
484 69149 array = (lbm_array_header_t *)lbm_malloc(sizeof(lbm_array_header_t));
485
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 69133 times.
69149 if (array == NULL) {
486 16 lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
487 16 return ENC_SYM_MERROR;
488 }
489
490 69133 bool r = lbm_start_flatten(&fv, (lbm_uint)required_mem);
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69133 times.
69133 if (!r) {
492 lbm_free(array);
493 lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
494 return ENC_SYM_MERROR;
495 }
496
497
1/2
✓ Branch 0 taken 69133 times.
✗ Branch 1 not taken.
69133 if (flatten_value_c(&fv, v) == FLATTEN_VALUE_OK) {
498 // it would be wasteful to run finish_flatten here.
499 69133 r = true;
500 } else {
501 r = false;
502 }
503
504
1/2
✓ Branch 0 taken 69133 times.
✗ Branch 1 not taken.
69133 if (r) {
505 // lift flat_value
506 69133 array->data = (lbm_uint*)fv.buf;
507 69133 array->size = fv.buf_size;
508 69133 lbm_set_car(array_cell, (lbm_uint)array);
509 69133 array_cell = lbm_set_ptr_type(array_cell, LBM_TYPE_ARRAY);
510 69133 return array_cell;
511 }
512 }
513 56 lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
514 56 return handle_flatten_error(required_mem);
515 }
516
517 // ------------------------------------------------------------
518 // Unflattening
519 122658 static bool extract_byte(lbm_flat_value_t *v, uint8_t *r) {
520
1/2
✓ Branch 0 taken 122658 times.
✗ Branch 1 not taken.
122658 if (v->buf_size >= v->buf_pos + 1) {
521 122658 *r = v->buf[v->buf_pos++];
522 122658 return true;
523 }
524 return false;
525 }
526
527 426811 static bool extract_word(lbm_flat_value_t *v, uint32_t *r) {
528 426811 bool res = false;
529
1/2
✓ Branch 0 taken 426811 times.
✗ Branch 1 not taken.
426811 if (v->buf_size >= v->buf_pos + 4) {
530 426811 uint32_t tmp = 0;
531 426811 tmp |= (lbm_value)v->buf[v->buf_pos++];
532 426811 tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++];
533 426811 tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++];
534 426811 tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++];
535 426811 *r = tmp;
536 426811 res = true;
537 }
538 426811 return res;
539 }
540
541 48998 static bool extract_dword(lbm_flat_value_t *v, uint64_t *r) {
542 48998 bool res = false;
543
1/2
✓ Branch 0 taken 48998 times.
✗ Branch 1 not taken.
48998 if (v->buf_size >= v->buf_pos + 8) {
544 48998 uint64_t tmp = 0;
545 48998 tmp |= (lbm_value)v->buf[v->buf_pos++];
546 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
547 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
548 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
549 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
550 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
551 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
552 48998 tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
553 48998 *r = tmp;
554 48998 res = true;;
555 }
556 48998 return res;
557 }
558
559 724526 static int lbm_unflatten_value_atom(lbm_flat_value_t *v, lbm_value *res) {
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 724526 times.
724526 if (v->buf_size == v->buf_pos) return UNFLATTEN_MALFORMED;
561
562 724526 uint8_t curr = v->buf[v->buf_pos++];
563
564
15/17
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 8305 times.
✓ Branch 3 taken 122658 times.
✓ Branch 4 taken 47323 times.
✓ Branch 5 taken 32 times.
✓ Branch 6 taken 45744 times.
✓ Branch 7 taken 28 times.
✓ Branch 8 taken 12498 times.
✓ Branch 9 taken 58 times.
✓ Branch 10 taken 58804 times.
✓ Branch 11 taken 63258 times.
✓ Branch 12 taken 58 times.
✓ Branch 13 taken 58 times.
✓ Branch 14 taken 239387 times.
✓ Branch 15 taken 126314 times.
✗ Branch 16 not taken.
724526 switch(curr) {
565 case S_CONS: {
566 return UNFLATTEN_MALFORMED;
567 }
568 1 case S_CONSTANT_REF: {
569 lbm_uint tmp;
570 bool b;
571 #ifndef LBM64
572 1 b = extract_word(v, &tmp);
573 #else
574 b = extract_dword(v, &tmp);
575 #endif
576
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (b) {
577 1 *res = tmp;
578 1 return UNFLATTEN_OK;
579 }
580 return UNFLATTEN_MALFORMED;
581 }
582 8305 case S_SYM_VALUE: {
583 lbm_uint tmp;
584 bool b;
585 #ifndef LBM64
586 5253 b = extract_word(v, &tmp);
587 #else
588 3052 b = extract_dword(v, &tmp);
589 #endif
590
1/2
✓ Branch 0 taken 8305 times.
✗ Branch 1 not taken.
8305 if (b) {
591 8305 *res = lbm_enc_sym(tmp);
592 8305 return UNFLATTEN_OK;
593 }
594 return UNFLATTEN_MALFORMED;
595 }
596 122658 case S_BYTE_VALUE: {
597 uint8_t tmp;
598 122658 bool b = extract_byte(v, &tmp);
599
1/2
✓ Branch 0 taken 122658 times.
✗ Branch 1 not taken.
122658 if (b) {
600 122658 *res = lbm_enc_char((uint8_t)tmp);
601 122658 return UNFLATTEN_OK;
602 }
603 return UNFLATTEN_MALFORMED;
604 }
605 47323 case S_I28_VALUE: {
606 uint32_t tmp;
607 bool b;
608 47323 b = extract_word(v, &tmp);
609
1/2
✓ Branch 0 taken 47323 times.
✗ Branch 1 not taken.
47323 if (b) {
610 47323 *res = lbm_enc_i((int32_t)tmp);
611 47323 return UNFLATTEN_OK;
612 }
613 return UNFLATTEN_MALFORMED;
614 }
615 32 case S_U28_VALUE: {
616 uint32_t tmp;
617 bool b;
618 32 b = extract_word(v, &tmp);
619
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if (b) {
620 32 *res = lbm_enc_u((uint32_t)tmp);
621 32 return UNFLATTEN_OK;
622 }
623 return UNFLATTEN_MALFORMED;
624 }
625 45744 case S_I56_VALUE: {
626 uint64_t tmp;
627 bool b;
628 45744 b = extract_dword(v, &tmp);
629
1/2
✓ Branch 0 taken 45744 times.
✗ Branch 1 not taken.
45744 if (b) {
630 #ifndef LBM64
631 *res = lbm_enc_i64((int64_t)tmp);
632 #else
633 45744 *res = lbm_enc_i((int64_t)tmp);
634 #endif
635 45744 return UNFLATTEN_OK;
636 }
637 return UNFLATTEN_MALFORMED;
638 }
639 28 case S_U56_VALUE: {
640 uint64_t tmp;
641 bool b;
642 28 b = extract_dword(v, &tmp);
643
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (b) {
644 #ifndef LBM64
645 *res = lbm_enc_u64(tmp);
646 #else
647 28 *res = lbm_enc_u(tmp);
648 #endif
649 28 return UNFLATTEN_OK;
650 }
651 return UNFLATTEN_MALFORMED;
652 }
653 12498 case S_FLOAT_VALUE: {
654 uint32_t tmp;
655 bool b;
656 12498 b = extract_word(v, &tmp);
657
1/2
✓ Branch 0 taken 12498 times.
✗ Branch 1 not taken.
12498 if (b) {
658 lbm_float f;
659 12498 memcpy(&f, &tmp, sizeof(lbm_float));
660 12498 lbm_value im = lbm_enc_float(f);
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12498 times.
12498 if (lbm_is_symbol_merror(im)) {
662 return UNFLATTEN_GC_RETRY;
663 }
664 12498 *res = im;
665 12498 return UNFLATTEN_OK;
666 }
667 return UNFLATTEN_MALFORMED;
668 }
669 58 case S_DOUBLE_VALUE: {
670 uint64_t tmp;
671 bool b;
672 58 b = extract_dword(v, &tmp);
673
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (b) {
674 double f;
675 58 memcpy(&f, &tmp, sizeof(uint64_t));
676 58 lbm_value im = lbm_enc_double(f);
677
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (lbm_is_symbol_merror(im)) {
678 return UNFLATTEN_GC_RETRY;
679 }
680 58 *res = im;
681 58 return UNFLATTEN_OK;
682 }
683 return UNFLATTEN_MALFORMED;
684 }
685 58804 case S_I32_VALUE: {
686 uint32_t tmp;
687
1/2
✓ Branch 0 taken 58804 times.
✗ Branch 1 not taken.
58804 if (extract_word(v, &tmp)) {
688 58804 lbm_value im = lbm_enc_i32((int32_t)tmp);
689
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 58730 times.
58804 if (lbm_is_symbol_merror(im)) {
690 74 return UNFLATTEN_GC_RETRY;
691 }
692 58730 *res = im;
693 58730 return UNFLATTEN_OK;
694 }
695 return UNFLATTEN_MALFORMED;
696 }
697 63258 case S_U32_VALUE: {
698 uint32_t tmp;
699
1/2
✓ Branch 0 taken 63258 times.
✗ Branch 1 not taken.
63258 if (extract_word(v, &tmp)) {
700 63258 lbm_value im = lbm_enc_u32(tmp);
701
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 63234 times.
63258 if (lbm_is_symbol_merror(im)) {
702 24 return UNFLATTEN_GC_RETRY;
703 }
704 63234 *res = im;
705 63234 return UNFLATTEN_OK;
706 }
707 return UNFLATTEN_MALFORMED;
708 }
709 58 case S_I64_VALUE: {
710 58 uint64_t tmp = 0;
711
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (extract_dword(v, &tmp)) {
712 58 lbm_value im = lbm_enc_i64((int64_t)tmp);
713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (lbm_is_symbol_merror(im)) {
714 return UNFLATTEN_GC_RETRY;
715 }
716 58 *res = im;
717 58 return UNFLATTEN_OK;
718 }
719 return UNFLATTEN_MALFORMED;
720 }
721 58 case S_U64_VALUE: {
722 58 uint64_t tmp = 0;
723
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (extract_dword(v, &tmp)) {
724 58 lbm_value im = lbm_enc_u64(tmp);
725
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (lbm_is_symbol_merror(im)) {
726 return UNFLATTEN_GC_RETRY;
727 }
728 58 *res = im;
729 58 return UNFLATTEN_OK;
730 }
731 return UNFLATTEN_MALFORMED;
732 }
733 239387 case S_LBM_ARRAY: {
734 uint32_t num_elt;
735
1/2
✓ Branch 0 taken 239387 times.
✗ Branch 1 not taken.
239387 if (extract_word(v, &num_elt)) {
736
2/2
✓ Branch 0 taken 238921 times.
✓ Branch 1 taken 466 times.
239387 if (lbm_heap_allocate_array(res, num_elt)) {
737 238921 lbm_array_header_t *arr = (lbm_array_header_t*)lbm_car(*res);
738 238921 lbm_uint num_bytes = num_elt;
739 238921 memcpy(arr->data, v->buf + v->buf_pos, num_bytes);
740 238921 v->buf_pos += num_bytes;
741 } else {
742 466 return UNFLATTEN_GC_RETRY;
743 }
744 238921 return UNFLATTEN_OK;
745 }
746 return UNFLATTEN_MALFORMED;
747 }
748 126314 case S_SYM_STRING: {
749 lbm_uint sym_id;
750
1/2
✓ Branch 0 taken 126314 times.
✗ Branch 1 not taken.
126314 if (lbm_add_symbol((char *)(v->buf + v->buf_pos), &sym_id)) {
751 126314 lbm_uint num_bytes = strlen((char*)(v->buf + v->buf_pos)) + 1;
752 126314 v->buf_pos += num_bytes;
753 126314 *res = lbm_enc_sym(sym_id);
754 126314 return UNFLATTEN_OK;
755 }
756 return UNFLATTEN_GC_RETRY;
757 }
758 default:
759 return UNFLATTEN_MALFORMED;
760 }
761 }
762
763 // ////////////////////////////////////////////////////////////
764 // Pointer-reversal-esque "stackless" deserialization of
765 // flattened (serialized) trees.
766 //
767 // Initially:
768 // curr = LBM_NULL; v->buf = { ... }
769 //
770 // FORWARDS PHASE:
771 // Cons case:
772 // Reading conses from the buffer builds a backpointing list.
773 // Placeholder element acts as a 1 bit "visited" field.
774 //
775 // curr = p; v->buf = {S_CONS, ... }
776 // =>
777 // curr = [p, placeholder]; v->buf = { ... }
778 //
779 // Lisp array case:
780 // An Array tag in the buffer leads to the creation of an array
781 // with a backptr in the last element position. Placeholder element
782 // is not needed as LBM-Arrays have a built in index field (used by GC)
783 // that can keep a count of how far along the array we have progressed.
784 //
785 // curr = p; v->buf = {S_LBM_LISP_ARRAY, ... }
786 // =>
787 // curr = [| nil ... p |]; v->buf = { ... }
788 //
789 // Atom case:
790 // Reading an atom triggers a backwards traversal along the backpointer
791 // structure.
792 //
793 // curr = X; v->buf = {any_atom, ... } example integer, string.
794 // =>
795 // val = unflatten_atom(v->buf); v->buf = { ... }
796 //
797 // BACKWARDS PHASE: Start the backwards traversal:
798 //
799 // Case on X
800 // LBM_NULL;
801 // => Done! result = val
802 //
803 // [p, placeholder];
804 // =>
805 // [p, val] Base case. Finishes back traversal.
806 // Go back to FORWARDS PHASE.
807 //
808 //
809 // [p, val0];
810 // =>
811 // tmp = [val0, val]; val = tmp; curr = p; continue backwards with value pointing to recently constructed final subresult.
812 //
813 //
814 // [| a b nil ... p |]
815 // =>
816 // [| a b val ... p |] Base case. Finishes back traversal.
817 // Array internal index field keeps track of write position.
818 // Go back to FORWARDS PHASE.
819 //
820 //
821 // [| a0 a1 ... an p |]
822 // =>
823 // tmp = [| a0 a1 ... an val |]; val = tmp; curr = p; continue backwards
824 //
825
826 77122 static int lbm_unflatten_value_nostack(sharing_table *st, lbm_uint *target_map, lbm_flat_value_t *v, lbm_value *res) {
827 77122 bool done = false;
828 lbm_value val0;
829 77122 lbm_value curr = lbm_enc_cons_ptr(LBM_PTR_NULL);
830
1/2
✓ Branch 0 taken 1373120 times.
✗ Branch 1 not taken.
1373120 while (!done) {
831 1373120 int32_t set_ix = -1;
832
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1373111 times.
1373120 if (v->buf[v->buf_pos] == S_SHARED) {
833 9 v->buf_pos++;
834
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18 if (st && target_map) {
835 9 bool b = false;
836 lbm_uint tmp;
837 #ifndef LBM64
838 9 b = extract_word(v, &tmp);
839 #else
840 b = extract_dword(v, &tmp);
841 #endif
842
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (b) {
843 9 int32_t ix = sharing_table_contains(st, tmp);
844
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (ix >= 0) {
845 9 set_ix = ix;
846 } else {
847 return UNFLATTEN_SHARING_TABLE_ERROR;
848 }
849 } else {
850 return UNFLATTEN_MALFORMED;
851 }
852 } else {
853 return UNFLATTEN_SHARING_TABLE_REQUIRED;
854 }
855 }
856
857 1373120 bool is_leaf = true;
858 1373120 lbm_value unflattened = ENC_SYM_NIL;
859
860
2/2
✓ Branch 0 taken 648348 times.
✓ Branch 1 taken 724772 times.
1373120 if (v->buf[v->buf_pos] == S_CONS) {
861 648348 lbm_value tmp = curr;
862 648348 curr = lbm_cons(tmp, ENC_SYM_PLACEHOLDER);
863
2/2
✓ Branch 0 taken 498 times.
✓ Branch 1 taken 647850 times.
648348 if (lbm_is_symbol_merror(curr)) return UNFLATTEN_GC_RETRY;
864
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 647841 times.
647850 if (set_ix >= 0) target_map[set_ix] = curr;
865 647850 v->buf_pos ++;
866 647850 is_leaf = false;
867
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 724535 times.
724772 } else if (v->buf[v->buf_pos] == S_LBM_LISP_ARRAY) {
868 uint32_t size;
869 237 v->buf_pos ++;
870 237 bool b = extract_word(v, &size);
871
1/2
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
237 if (b) {
872 lbm_value array;
873 237 lbm_heap_allocate_lisp_array(&array, size);
874 237 lbm_array_header_extended_t *header = (lbm_array_header_extended_t*)lbm_car(array);
875
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 235 times.
237 if (size == 0) {
876 2 unflattened = array;
877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (set_ix >= 0) target_map[set_ix] = array;
878 } else {
879 235 is_leaf = false;
880 235 lbm_value *arrdata = (lbm_value*)header->data;
881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 if (lbm_is_symbol_merror(array)) return UNFLATTEN_GC_RETRY;
882 235 header->index = 0;
883 235 arrdata[size-1] = curr; // backptr
884 235 curr = array;
885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 if (set_ix >= 0) target_map[set_ix] = curr;
886 }
887 } else {
888 return UNFLATTEN_MALFORMED;
889 }
890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 724535 times.
724535 } else if (v->buf[v->buf_pos] == 0) {
891 return UNFLATTEN_MALFORMED;
892
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 724526 times.
724535 } else if (v->buf[v->buf_pos] == S_REF) {
893 9 v->buf_pos++;
894
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18 if (st && target_map) {
895 9 bool b = false;
896 lbm_uint tmp;
897 #ifndef LBM64
898 9 b = extract_word(v, &tmp);
899 #else
900 b = extract_dword(v, &tmp);
901 #endif
902
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (b) {
903 // Shared should have been hit before S_REF. So just look up index and copy from
904 // the target_map.
905 9 int32_t ix = sharing_table_contains(st, tmp);
906
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (ix >= 0) {
907 //curr = target_map[ix];
908 9 unflattened = target_map[ix];
909 } else {
910 return UNFLATTEN_SHARING_TABLE_ERROR;
911 }
912 } else {
913 return UNFLATTEN_MALFORMED;
914 }
915 } else {
916 return UNFLATTEN_SHARING_TABLE_REQUIRED;
917 }
918 } else {
919 724526 int e_val = lbm_unflatten_value_atom(v, &unflattened);
920
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 724526 times.
724526 if (set_ix >= 0) {
921 target_map[set_ix] = unflattened;
922 }
923
2/2
✓ Branch 0 taken 564 times.
✓ Branch 1 taken 723962 times.
724526 if (e_val != UNFLATTEN_OK) {
924 564 return e_val;
925 }
926 }
927
928
2/2
✓ Branch 0 taken 723973 times.
✓ Branch 1 taken 648085 times.
1372058 if (is_leaf) {
929 723973 val0 = unflattened;
930
4/4
✓ Branch 0 taken 1291180 times.
✓ Branch 1 taken 76060 times.
✓ Branch 2 taken 643894 times.
✓ Branch 3 taken 647286 times.
2658420 while (lbm_dec_ptr(curr) != LBM_PTR_NULL &&
931 1291180 lbm_cdr(curr) != ENC_SYM_PLACEHOLDER) { // has done left
932
2/2
✓ Branch 0 taken 862 times.
✓ Branch 1 taken 643032 times.
643894 if ( lbm_type_of(curr) == LBM_TYPE_LISPARRAY) {
933 862 lbm_array_header_extended_t *header = (lbm_array_header_extended_t*)lbm_car(curr);
934 862 lbm_value *arrdata = (lbm_value*)header->data;
935 862 uint32_t arrlen = header->size / sizeof(lbm_value);
936
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 627 times.
862 if (header->index == arrlen - 1) {
937 235 lbm_value prev = arrdata[arrlen-1];
938 235 header->index = 0;
939 235 arrdata[arrlen-1] = val0;
940 235 val0 = curr;
941 235 curr = prev;
942 } else {
943 627 arrdata[header->index++] = val0;
944 627 break;
945 }
946 } else {
947 643032 lbm_value prev = lbm_car(curr);
948 643032 lbm_value r0 = lbm_cdr(curr);
949 643032 lbm_set_cdr(curr, val0);
950 643032 lbm_set_car(curr, r0);
951 643032 val0 = curr;
952 643032 curr = prev;
953 }
954 }
955
2/2
✓ Branch 0 taken 76060 times.
✓ Branch 1 taken 647913 times.
723973 if (lbm_dec_ptr(curr) == LBM_PTR_NULL) {
956 76060 *res = val0; // done
957 76060 break;
958
2/2
✓ Branch 0 taken 647286 times.
✓ Branch 1 taken 627 times.
647913 } else if (lbm_type_of(curr) == LBM_TYPE_LISPARRAY) {
959 // Do nothing in this case. It has been arranged..
960
1/2
✓ Branch 0 taken 647286 times.
✗ Branch 1 not taken.
647286 } else if (lbm_cdr(curr) == ENC_SYM_PLACEHOLDER) {
961 647286 lbm_set_cdr(curr, val0);
962 } else {
963 return UNFLATTEN_MALFORMED;
964 }
965 }
966 }
967 76060 return UNFLATTEN_OK;
968 }
969
970 /* lbm_unflatten_value_nostack, does not backtrack
971 upon error to swap pointer to the correct direction
972 and to remove the LBM_PTR_NULL tag.
973
974 unflatten_value_nostack does not alter the GC_FLAG or the GC_MARK,
975 So really only reverse pointers and the NIL tag could be
976 potential problems.
977 */
978 76034 bool lbm_unflatten_value(lbm_flat_value_t *v, lbm_value *res) {
979 76034 bool b = false;
980 #ifdef LBM_ALWAYS_GC
981 lbm_perform_gc();
982 #endif
983 76034 int r = lbm_unflatten_value_nostack(NULL,NULL, v,res);
984
2/2
✓ Branch 0 taken 1062 times.
✓ Branch 1 taken 74972 times.
76034 if (r == UNFLATTEN_GC_RETRY) {
985 1062 lbm_perform_gc();
986 1062 v->buf_pos = 0;
987 1062 r = lbm_unflatten_value_nostack(NULL,NULL,v,res);
988 }
989
1/3
✓ Branch 0 taken 76034 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
76034 switch(r) {
990 76034 case UNFLATTEN_OK:
991 76034 b = true;
992 76034 break;
993 case UNFLATTEN_GC_RETRY:
994 *res = ENC_SYM_MERROR;
995 break;
996 default:
997 *res = ENC_SYM_EERROR;
998 break;
999 }
1000 // Do not free the flat value buffer here.
1001 // there are 2 cases:
1002 // 1: unflatten was called from lisp code -> GC removes the buffer.
1003 // 2: unflatten called from event processing -> event processor frees buffer.
1004 76034 return b;
1005 }
1006
1007 26 bool lbm_unflatten_value_sharing(sharing_table *st, lbm_uint *target_map, lbm_flat_value_t *v, lbm_value *res) {
1008 26 bool b = false;
1009 #ifdef LBM_ALWAYS_GC
1010 lbm_perform_gc();
1011 #endif
1012 26 int r = lbm_unflatten_value_nostack(st,target_map, v,res);
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (r == UNFLATTEN_GC_RETRY) {
1014 lbm_perform_gc();
1015 v->buf_pos = 0;
1016 r = lbm_unflatten_value_nostack(st,target_map,v,res);
1017 }
1018
1/3
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
26 switch(r) {
1019 26 case UNFLATTEN_OK:
1020 26 b = true;
1021 26 break;
1022 case UNFLATTEN_GC_RETRY:
1023 *res = ENC_SYM_MERROR;
1024 break;
1025 default:
1026 *res = ENC_SYM_EERROR;
1027 break;
1028 }
1029 // Do not free the flat value buffer here.
1030 // there are 2 cases:
1031 // 1: unflatten was called from lisp code -> GC removes the buffer.
1032 // 2: unflatten called from event processing -> event processor frees buffer.
1033 26 return b;
1034 }
1035