Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2014-2017 Paul Sokolovsky
7 : : * Copyright (c) 2014-2019 Damien P. George
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : : * of this software and associated documentation files (the "Software"), to deal
11 : : * in the Software without restriction, including without limitation the rights
12 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : : * copies of the Software, and to permit persons to whom the Software is
14 : : * furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included in
17 : : * all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 : : * THE SOFTWARE.
26 : : */
27 : :
28 : : #include <stdint.h>
29 : : #include <stdlib.h>
30 : : #include <stddef.h>
31 : : #include <string.h>
32 : : #include <assert.h>
33 : :
34 : : #include "py/binary.h"
35 : : #include "py/smallint.h"
36 : : #include "py/objint.h"
37 : : #include "py/runtime.h"
38 : :
39 : : // Helpers to work with binary-encoded data
40 : :
41 : : #ifndef alignof
42 : : #define alignof(type) offsetof(struct { char c; type t; }, t)
43 : : #endif
44 : :
45 : 21790 : size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) {
46 : 21790 : size_t size = 0;
47 : 21790 : int align = 1;
48 [ + + - ]: 21790 : switch (struct_type) {
49 : 1864 : case '<':
50 : : case '>':
51 [ + + + + : 1864 : switch (val_type) {
+ + + -
+ ]
52 : : case 'b':
53 : : case 'B':
54 : 292 : size = 1;
55 : 292 : break;
56 : : case 'h':
57 : : case 'H':
58 : : size = 2;
59 : : break;
60 : : case 'i':
61 : : case 'I':
62 : 276 : size = 4;
63 : 276 : break;
64 : : case 'l':
65 : : case 'L':
66 : 16 : size = 4;
67 : 16 : break;
68 : : case 'q':
69 : : case 'Q':
70 : 264 : size = 8;
71 : 264 : break;
72 : : case 'P':
73 : : case 'O':
74 : : case 'S':
75 : 32 : size = sizeof(void *);
76 : 32 : break;
77 : : case 'e':
78 : : size = 2;
79 : : break;
80 : : case 'f':
81 : 44 : size = 4;
82 : 44 : break;
83 : : case 'd':
84 : 48 : size = 8;
85 : 48 : break;
86 : : }
87 : : break;
88 : 19926 : case '@': {
89 : : // TODO:
90 : : // The simplest heuristic for alignment is to align by value
91 : : // size, but that doesn't work for "bigger than int" types,
92 : : // for example, long long may very well have long alignment
93 : : // So, we introduce separate alignment handling, but having
94 : : // formal support for that is different from actually supporting
95 : : // particular (or any) ABI.
96 [ + + + + : 19926 : switch (val_type) {
+ + + ]
97 : : case BYTEARRAY_TYPECODE:
98 : : case 'b':
99 : : case 'B':
100 : 16930 : align = size = 1;
101 : 16930 : break;
102 : : case 'h':
103 : : case 'H':
104 : 616 : align = alignof(short);
105 : 616 : size = sizeof(short);
106 : 616 : break;
107 : : case 'i':
108 : : case 'I':
109 : 716 : align = alignof(int);
110 : 716 : size = sizeof(int);
111 : 716 : break;
112 : : case 'l':
113 : : case 'L':
114 : : align = alignof(long);
115 : : size = sizeof(long);
116 : : break;
117 : : case 'q':
118 : : case 'Q':
119 : : align = alignof(long long);
120 : : size = sizeof(long long);
121 : : break;
122 : : case 'P':
123 : : case 'O':
124 : : case 'S':
125 : : align = alignof(void *);
126 : : size = sizeof(void *);
127 : : break;
128 : : case 'e':
129 : 24 : align = 2;
130 : 24 : size = 2;
131 : 24 : break;
132 : : case 'f':
133 : 236 : align = alignof(float);
134 : 236 : size = sizeof(float);
135 : 236 : break;
136 : : case 'd':
137 : : align = alignof(double);
138 : : size = sizeof(double);
139 : : break;
140 : : }
141 : : }
142 : : }
143 : :
144 : 19494 : if (size == 0) {
145 : 40 : mp_raise_ValueError(MP_ERROR_TEXT("bad typecode"));
146 : : }
147 : :
148 [ + + ]: 21750 : if (palign != NULL) {
149 : 2122 : *palign = align;
150 : : }
151 : 21750 : return size;
152 : : }
153 : :
154 : : #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_USE_NATIVE_FLT16
155 : :
156 : : static inline float mp_decode_half_float(uint16_t hf) {
157 : : union {
158 : : uint16_t i;
159 : : _Float16 f;
160 : : } fpu = { .i = hf };
161 : : return fpu.f;
162 : : }
163 : :
164 : : static inline uint16_t mp_encode_half_float(float x) {
165 : : union {
166 : : uint16_t i;
167 : : _Float16 f;
168 : : } fp_sp = { .f = (_Float16)x };
169 : : return fp_sp.i;
170 : : }
171 : :
172 : : #elif MICROPY_PY_BUILTINS_FLOAT
173 : :
174 : 164 : static float mp_decode_half_float(uint16_t hf) {
175 : 164 : union {
176 : : uint32_t i;
177 : : float f;
178 : : } fpu;
179 : :
180 : 164 : uint16_t m = hf & 0x3ff;
181 : 164 : int e = (hf >> 10) & 0x1f;
182 [ + + ]: 164 : if (e == 0x1f) {
183 : : // Half-float is infinity.
184 : : e = 0xff;
185 [ + + ]: 156 : } else if (e) {
186 : : // Half-float is normal.
187 : 116 : e += 127 - 15;
188 [ + + ]: 40 : } else if (m) {
189 : : // Half-float is subnormal, make it normal.
190 : : e = 127 - 15;
191 [ + + ]: 248 : while (!(m & 0x400)) {
192 : 216 : m <<= 1;
193 : 216 : --e;
194 : : }
195 : 32 : m -= 0x400;
196 : 32 : ++e;
197 : : }
198 : :
199 : 164 : fpu.i = ((hf & 0x8000) << 16) | (e << 23) | (m << 13);
200 : 164 : return fpu.f;
201 : : }
202 : :
203 : 168 : static uint16_t mp_encode_half_float(float x) {
204 : 168 : union {
205 : : uint32_t i;
206 : : float f;
207 : 168 : } fpu = { .f = x };
208 : :
209 : 168 : uint16_t m = (fpu.i >> 13) & 0x3ff;
210 [ + + ]: 168 : if (fpu.i & (1 << 12)) {
211 : : // Round up.
212 : 52 : ++m;
213 : : }
214 : 168 : int e = (fpu.i >> 23) & 0xff;
215 : :
216 [ + + ]: 168 : if (e == 0xff) {
217 : : // Infinity.
218 : : e = 0x1f;
219 [ + + ]: 160 : } else if (e != 0) {
220 : 152 : e -= 127 - 15;
221 [ + + ]: 152 : if (e < 0) {
222 : : // Underflow: denormalized, or zero.
223 [ + - ]: 32 : if (e >= -11) {
224 : 32 : m = (m | 0x400) >> -e;
225 [ + + ]: 32 : if (m & 1) {
226 : 24 : m = (m >> 1) + 1;
227 : : } else {
228 : 8 : m >>= 1;
229 : : }
230 : : } else {
231 : : m = 0;
232 : : }
233 : : e = 0;
234 [ + + ]: 120 : } else if (e > 0x3f) {
235 : : // Overflow: infinity.
236 : 4 : e = 0x1f;
237 : 4 : m = 0;
238 : : }
239 : : }
240 : :
241 : 168 : uint16_t bits = ((fpu.i >> 16) & 0x8000) | (e << 10) | m;
242 : 168 : return bits;
243 : : }
244 : :
245 : : #endif
246 : :
247 : 10425403 : mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {
248 : 10425403 : mp_int_t val = 0;
249 [ + + + + : 10425403 : switch (typecode) {
+ + + + +
+ + + + +
- ]
250 : 32 : case 'b':
251 : 32 : val = ((signed char *)p)[index];
252 : 32 : break;
253 : 10414803 : case BYTEARRAY_TYPECODE:
254 : : case 'B':
255 : 10414803 : val = ((unsigned char *)p)[index];
256 : 10414803 : break;
257 : 10116 : case 'h':
258 : 10116 : val = ((short *)p)[index];
259 : 10116 : break;
260 : 32 : case 'H':
261 : 32 : val = ((unsigned short *)p)[index];
262 : 32 : break;
263 : 112 : case 'i':
264 : 112 : return mp_obj_new_int(((int *)p)[index]);
265 : 156 : case 'I':
266 : 156 : return mp_obj_new_int_from_uint(((unsigned int *)p)[index]);
267 : 16 : case 'l':
268 : 16 : return mp_obj_new_int(((long *)p)[index]);
269 : 12 : case 'L':
270 : 12 : return mp_obj_new_int_from_uint(((unsigned long *)p)[index]);
271 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
272 : 28 : case 'q':
273 : 28 : return mp_obj_new_int_from_ll(((long long *)p)[index]);
274 : 20 : case 'Q':
275 : 20 : return mp_obj_new_int_from_ull(((unsigned long long *)p)[index]);
276 : : #endif
277 : : #if MICROPY_PY_BUILTINS_FLOAT
278 : 36 : case 'f':
279 : 36 : return mp_obj_new_float_from_f(((float *)p)[index]);
280 : 32 : case 'd':
281 : 32 : return mp_obj_new_float_from_d(((double *)p)[index]);
282 : : #endif
283 : : // Extension to CPython: array of objects
284 : 4 : case 'O':
285 : 4 : return ((mp_obj_t *)p)[index];
286 : : // Extension to CPython: array of pointers
287 : 4 : case 'P':
288 : 4 : return mp_obj_new_int((mp_int_t)(uintptr_t)((void **)p)[index]);
289 : : }
290 : 10424983 : return MP_OBJ_NEW_SMALL_INT(val);
291 : : }
292 : :
293 : : // The long long type is guaranteed to hold at least 64 bits, and size is at
294 : : // most 8 (for q and Q), so we will always be able to parse the given data
295 : : // and fit it into a long long.
296 : 622 : long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src) {
297 : 622 : int delta;
298 [ + + ]: 622 : if (!big_endian) {
299 : 496 : delta = -1;
300 : 496 : src += size - 1;
301 : : } else {
302 : : delta = 1;
303 : : }
304 : :
305 : 622 : unsigned long long val = 0;
306 [ + + + + ]: 622 : if (is_signed && *src & 0x80) {
307 : 156 : val = -1;
308 : : }
309 [ + + ]: 2634 : for (uint i = 0; i < size; i++) {
310 : 2012 : val <<= 8;
311 : 2012 : val |= *src;
312 : 2012 : src += delta;
313 : : }
314 : :
315 : 622 : return val;
316 : : }
317 : :
318 : : #define is_signed(typecode) (typecode > 'Z')
319 : 592 : mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr) {
320 : 592 : byte *p = *ptr;
321 : 592 : size_t align;
322 : :
323 : 592 : size_t size = mp_binary_get_size(struct_type, val_type, &align);
324 [ + + ]: 592 : if (struct_type == '@') {
325 : : // Align p relative to p_base
326 : 48 : p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);
327 : : #if MP_ENDIANNESS_LITTLE
328 : 48 : struct_type = '<';
329 : : #else
330 : : struct_type = '>';
331 : : #endif
332 : : }
333 : 592 : *ptr = p + size;
334 : :
335 : 592 : long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
336 : :
337 [ + + + + : 592 : if (val_type == 'O') {
+ + ]
338 : 4 : return (mp_obj_t)(mp_uint_t)val;
339 : : } else if (val_type == 'S') {
340 : 4 : const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val;
341 : 4 : return mp_obj_new_str_from_cstr(s_val);
342 : : #if MICROPY_PY_BUILTINS_FLOAT
343 : : } else if (val_type == 'e') {
344 : 164 : return mp_obj_new_float_from_f(mp_decode_half_float(val));
345 : : } else if (val_type == 'f') {
346 : 18 : union {
347 : : uint32_t i;
348 : : float f;
349 : 18 : } fpu = {val};
350 : 18 : return mp_obj_new_float_from_f(fpu.f);
351 : : } else if (val_type == 'd') {
352 : 20 : union {
353 : : uint64_t i;
354 : : double f;
355 : 20 : } fpu = {val};
356 : 20 : return mp_obj_new_float_from_d(fpu.f);
357 : : #endif
358 [ + + ]: 382 : } else if (is_signed(val_type)) {
359 [ + + ]: 176 : if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {
360 : 172 : return mp_obj_new_int((mp_int_t)val);
361 : : } else {
362 : 4 : return mp_obj_new_int_from_ll(val);
363 : : }
364 : : } else {
365 [ + + ]: 206 : if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) {
366 : 190 : return mp_obj_new_int_from_uint((mp_uint_t)val);
367 : : } else {
368 : 16 : return mp_obj_new_int_from_ull(val);
369 : : }
370 : : }
371 : : }
372 : :
373 : 728 : void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
374 [ + + ]: 728 : if (MP_ENDIANNESS_LITTLE && !big_endian) {
375 : 504 : memcpy(dest, &val, val_sz);
376 : 224 : } else if (MP_ENDIANNESS_BIG && big_endian) {
377 : : // only copy the least-significant val_sz bytes
378 : : memcpy(dest, (byte *)&val + sizeof(mp_uint_t) - val_sz, val_sz);
379 : : } else {
380 : 224 : const byte *src;
381 : 224 : if (MP_ENDIANNESS_LITTLE) {
382 : 224 : src = (const byte *)&val + val_sz;
383 : : } else {
384 : : src = (const byte *)&val + sizeof(mp_uint_t);
385 : : }
386 [ + + ]: 1002 : while (val_sz--) {
387 : 778 : *dest++ = *--src;
388 : : }
389 : : }
390 : 728 : }
391 : :
392 : 642 : void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) {
393 : 642 : byte *p = *ptr;
394 : 642 : size_t align;
395 : :
396 : 642 : size_t size = mp_binary_get_size(struct_type, val_type, &align);
397 [ + + ]: 642 : if (struct_type == '@') {
398 : : // Align p relative to p_base
399 : 62 : p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);
400 : 62 : if (MP_ENDIANNESS_LITTLE) {
401 : 62 : struct_type = '<';
402 : : } else {
403 : : struct_type = '>';
404 : : }
405 : : }
406 : 642 : *ptr = p + size;
407 : :
408 : 642 : mp_uint_t val;
409 [ + + + + : 642 : switch (val_type) {
+ ]
410 : 4 : case 'O':
411 : 4 : val = (mp_uint_t)val_in;
412 : 4 : break;
413 : : #if MICROPY_PY_BUILTINS_FLOAT
414 : : case 'e':
415 : 168 : val = mp_encode_half_float(mp_obj_get_float_to_f(val_in));
416 : 168 : break;
417 : : case 'f': {
418 : 18 : union {
419 : : uint32_t i;
420 : : float f;
421 : : } fp_sp;
422 : 18 : fp_sp.f = mp_obj_get_float_to_f(val_in);
423 : 18 : val = fp_sp.i;
424 : 18 : break;
425 : : }
426 : : case 'd': {
427 : 20 : union {
428 : : uint64_t i64;
429 : : uint32_t i32[2];
430 : : double f;
431 : : } fp_dp;
432 : 20 : fp_dp.f = mp_obj_get_float_to_d(val_in);
433 : 20 : if (MP_BYTES_PER_OBJ_WORD == 8) {
434 : 20 : val = fp_dp.i64;
435 : : } else {
436 : : int be = struct_type == '>';
437 : : mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]);
438 : : p += sizeof(uint32_t);
439 : : val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be];
440 : : }
441 : 20 : break;
442 : : }
443 : : #endif
444 : : default:
445 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
446 [ + + + - ]: 432 : if (mp_obj_is_exact_type(val_in, &mp_type_int)) {
447 : 16 : mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
448 : 16 : return;
449 : : }
450 : : #endif
451 : :
452 : 416 : val = mp_obj_get_int(val_in);
453 : : // zero/sign extend if needed
454 : 416 : if (MP_BYTES_PER_OBJ_WORD < 8 && size > sizeof(val)) {
455 : : int c = (mp_int_t)val < 0 ? 0xff : 0x00;
456 : : memset(p, c, size);
457 : : if (struct_type == '>') {
458 : : p += size - sizeof(val);
459 : : }
460 : : }
461 : 416 : break;
462 : : }
463 : :
464 : 626 : mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
465 : : }
466 : :
467 : 7290054 : void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) {
468 [ + + + + ]: 7290054 : switch (typecode) {
469 : : #if MICROPY_PY_BUILTINS_FLOAT
470 : 48 : case 'f':
471 : 48 : ((float *)p)[index] = mp_obj_get_float_to_f(val_in);
472 : 48 : break;
473 : 24 : case 'd':
474 : 24 : ((double *)p)[index] = mp_obj_get_float_to_d(val_in);
475 : 24 : break;
476 : : #endif
477 : : // Extension to CPython: array of objects
478 : 4 : case 'O':
479 : 4 : ((mp_obj_t *)p)[index] = val_in;
480 : 4 : break;
481 : : default:
482 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
483 [ + + + - ]: 7289978 : if (mp_obj_is_exact_type(val_in, &mp_type_int)) {
484 : 16 : size_t size = mp_binary_get_size('@', typecode, NULL);
485 : 16 : mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
486 : 16 : size, (uint8_t *)p + index * size);
487 : 16 : return;
488 : : }
489 : : #endif
490 : 7289962 : mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
491 : : }
492 : : }
493 : :
494 : 7520272 : void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) {
495 [ + + + + : 7520272 : switch (typecode) {
+ + + + +
+ + + +
- ]
496 : 292 : case 'b':
497 : 292 : ((signed char *)p)[index] = val;
498 : 292 : break;
499 : 7519146 : case BYTEARRAY_TYPECODE:
500 : : case 'B':
501 : 7519146 : ((unsigned char *)p)[index] = val;
502 : 7519146 : break;
503 : 234 : case 'h':
504 : 234 : ((short *)p)[index] = val;
505 : 234 : break;
506 : 64 : case 'H':
507 : 64 : ((unsigned short *)p)[index] = val;
508 : 64 : break;
509 : 140 : case 'i':
510 : 140 : ((int *)p)[index] = val;
511 : 140 : break;
512 : 188 : case 'I':
513 : 188 : ((unsigned int *)p)[index] = val;
514 : 188 : break;
515 : 52 : case 'l':
516 : 52 : ((long *)p)[index] = val;
517 : 52 : break;
518 : 52 : case 'L':
519 : 52 : ((unsigned long *)p)[index] = val;
520 : 52 : break;
521 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
522 : 48 : case 'q':
523 : 48 : ((long long *)p)[index] = val;
524 : 48 : break;
525 : 48 : case 'Q':
526 : 48 : ((unsigned long long *)p)[index] = val;
527 : 48 : break;
528 : : #endif
529 : : #if MICROPY_PY_BUILTINS_FLOAT
530 : 2 : case 'f':
531 : 2 : ((float *)p)[index] = (float)val;
532 : 2 : break;
533 : 2 : case 'd':
534 : 2 : ((double *)p)[index] = (double)val;
535 : 2 : break;
536 : : #endif
537 : : // Extension to CPython: array of pointers
538 : 4 : case 'P':
539 : 4 : ((void **)p)[index] = (void *)(uintptr_t)val;
540 : 4 : break;
541 : : }
542 : 7520272 : }
|