diff --git a/py/mpz.c b/py/mpz.c index b61997e2fd4ed..65bb3af182c66 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -850,25 +850,43 @@ size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigne return cur - str; } -void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf) { +void mpz_set_from_bytes(mpz_t *z, bool is_signed, bool big_endian, size_t len, const byte *buf) { int delta = 1; if (big_endian) { + z->neg = is_signed && (buf[0] & 0x80); buf += len - 1; delta = -1; + } else { + z->neg = is_signed && (buf[len - 1] & 0x80); } mpz_need_dig(z, (len * 8 + DIG_SIZE - 1) / DIG_SIZE); mpz_dig_t d = 0; + byte carry = 1; int num_bits = 0; - z->neg = 0; z->len = 0; while (len) { - while (len && num_bits < DIG_SIZE) { - d |= *buf << num_bits; + while (num_bits < DIG_SIZE) { + byte b; + if (len) { + b = *buf; + buf += delta; + len--; + } else if (z->neg) { + // sign-extend missing bytes + b = 0xff; + } else { + b = 0; + } + + if (z->neg) { + b = (~b) + carry; + carry &= b == 0; + } + + d |= b << num_bits; num_bits += 8; - buf += delta; - len--; } z->dig[z->len++] = d & DIG_MASK; // Need this #if because it's C undefined behavior to do: uint32_t >> 32 diff --git a/py/mpz.h b/py/mpz.h index d27f5724047ae..b266bd9817ead 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -114,7 +114,7 @@ void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed); void mpz_set_from_float(mpz_t *z, mp_float_t src); #endif size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base); -void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf); +void mpz_set_from_bytes(mpz_t *z, bool is_signed, bool big_endian, size_t len, const byte *buf); static inline bool mpz_is_zero(const mpz_t *z) { return z->len == 0; diff --git a/py/objint.c b/py/objint.c index be5f4653a7dec..9275b82d83992 100644 --- a/py/objint.c +++ b/py/objint.c @@ -409,7 +409,7 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (value > (MP_SMALL_INT_MAX >> 8)) { // Result will overflow a small-int so construct a big-int - return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); + return mp_obj_int_from_bytes_impl(false, args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); } #endif value = (value << 8) | *buf; diff --git a/py/objint.h b/py/objint.h index 5eed87705dedb..560aa2263d7fe 100644 --- a/py/objint.h +++ b/py/objint.h @@ -54,7 +54,8 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); mp_int_t mp_obj_int_hash(mp_obj_t self_in); -mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); +mp_obj_t mp_obj_int_from_bytes_impl(bool is_signed, bool big_endian, size_t len, const byte *buf); +size_t mp_obj_int_max_bytes_needed_impl(mp_obj_t self_in); void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); int mp_obj_int_sign(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index ee499e0265b32..f3fc2fa9c8dfe 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -43,7 +43,7 @@ const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif -mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { +mp_obj_t mp_obj_int_from_bytes_impl(bool is_signed, bool big_endian, size_t len, const byte *buf) { int delta = 1; if (!big_endian) { buf += len - 1; @@ -57,6 +57,11 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf return mp_obj_new_int_from_ll(value); } +size_t mp_obj_int_max_bytes_needed_impl(mp_obj_t self_in) { + assert(mp_obj_is_exact_type(self_in, &mp_type_int)); + return sizeof(mp_longint_impl_t); +} + void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(mp_obj_is_exact_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 8078441d66a0b..11d44a23e5b44 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -106,12 +106,19 @@ char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, return str; } -mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { +mp_obj_t mp_obj_int_from_bytes_impl(bool is_signed, bool big_endian, size_t len, const byte *buf) { mp_obj_int_t *o = mp_obj_int_new_mpz(); - mpz_set_from_bytes(&o->mpz, big_endian, len, buf); + mpz_set_from_bytes(&o->mpz, is_signed, big_endian, len, buf); return MP_OBJ_FROM_PTR(o); } +size_t mp_obj_int_max_bytes_needed_impl(mp_obj_t self_in) { + assert(mp_obj_is_exact_type(self_in, &mp_type_int)); + mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + // two's complement may require one more bit than the magnitude itself + return (mpz_max_num_bits(&self->mpz) + 1 + 7) / 8; +} + void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(mp_obj_is_exact_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/py/persistentcode.c b/py/persistentcode.c index fdc87d5cc8c3a..3d41fddb0098e 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -24,17 +24,22 @@ * THE SOFTWARE. */ +#include #include #include #include #include +#include "py/binary.h" +#include "py/obj.h" +#include "py/objint.h" #include "py/reader.h" #include "py/nativeglue.h" #include "py/persistentcode.h" #include "py/bc0.h" #include "py/objstr.h" #include "py/mpthread.h" +#include "py/misc.h" #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE @@ -170,6 +175,49 @@ STATIC qstr load_qstr(mp_reader_t *reader) { return qst; } +#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE +STATIC mp_float_t mp_read_float_binary(mp_reader_t *reader, bool is_double) { + size_t len = is_double ? 8 : 4; + // native-endian buffer + byte buf[8]; + + #if MP_ENDIANNESS_LITTLE + read_bytes(reader, buf, len); + #else + for (int i = len - 1; i >= 0; i--) { + const byte b = read_byte(reader); + buf[i] = b; + } + #endif + + if (is_double) { + union double_int_union { + double f; + int64_t i; + } u; + memcpy(&u.i, buf, len); + + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + return u.f; + #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + return (mp_float_t)u.f; + #endif + } else { + union float_int_union { + float f; + int32_t i; + } u; + memcpy(&u.i, buf, len); + + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + return (mp_float_t)u.f; + #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + return u.f; + #endif + } +} +#endif + STATIC mp_obj_t load_obj(mp_reader_t *reader) { byte obj_type = read_byte(reader); #if MICROPY_EMIT_MACHINE_CODE @@ -185,7 +233,47 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { return mp_const_true; } else if (obj_type == MP_PERSISTENT_OBJ_ELLIPSIS) { return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj); - } else { + } else if (obj_type == MP_PERSISTENT_OBJ_INT) { + size_t len_neg = read_uint(reader); + size_t len = len_neg >> 1; + bool is_negative = len_neg & 1; + + vstr_t vstr; + vstr_init_len(&vstr, len); + read_bytes(reader, (byte *)vstr.buf, len); + + if (len > sizeof(mp_int_t)) { + // definitely too big for small int + return mp_obj_int_from_bytes_impl(is_negative, false, len, (byte *)vstr.buf); + } + + mp_int_t val = mp_binary_get_int(len, is_negative, false, (byte *)vstr.buf); + + if (!MP_SMALL_INT_FITS(val) || (!is_negative && val < 0)) { + // still didn't fit in small int + return mp_obj_int_from_bytes_impl(is_negative, false, len, (byte *)vstr.buf); + } else { + return MP_OBJ_NEW_SMALL_INT(val); + } + } + #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE + #if MICROPY_PY_BUILTINS_COMPLEX + else if (obj_type == MP_PERSISTENT_OBJ_COMPLEX_FLOAT || + obj_type == MP_PERSISTENT_OBJ_COMPLEX_DOUBLE) { + bool is_double = obj_type == MP_PERSISTENT_OBJ_COMPLEX_DOUBLE; + mp_float_t real = mp_read_float_binary(reader, is_double); + mp_float_t imag = mp_read_float_binary(reader, is_double); + return mp_obj_new_complex(real, imag); + } + #endif + else if (obj_type == MP_PERSISTENT_OBJ_FP_FLOAT || + obj_type == MP_PERSISTENT_OBJ_FP_DOUBLE) { + bool is_double = obj_type == MP_PERSISTENT_OBJ_FP_DOUBLE; + mp_float_t f = mp_read_float_binary(reader, is_double); + return mp_obj_new_float(f); + } + #endif + else { size_t len = read_uint(reader); if (len == 0 && obj_type == MP_PERSISTENT_OBJ_BYTES) { read_byte(reader); // skip null terminator @@ -197,21 +285,16 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { } return MP_OBJ_FROM_PTR(tuple); } + + assert(obj_type == MP_PERSISTENT_OBJ_STR || obj_type == MP_PERSISTENT_OBJ_BYTES); vstr_t vstr; vstr_init_len(&vstr, len); read_bytes(reader, (byte *)vstr.buf, len); - if (obj_type == MP_PERSISTENT_OBJ_STR || obj_type == MP_PERSISTENT_OBJ_BYTES) { - read_byte(reader); // skip null terminator - if (obj_type == MP_PERSISTENT_OBJ_STR) { - return mp_obj_new_str_from_utf8_vstr(&vstr); - } else { - return mp_obj_new_bytes_from_vstr(&vstr); - } - } else if (obj_type == MP_PERSISTENT_OBJ_INT) { - return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); + read_byte(reader); // skip null terminator + if (obj_type == MP_PERSISTENT_OBJ_STR) { + return mp_obj_new_str_from_utf8_vstr(&vstr); } else { - assert(obj_type == MP_PERSISTENT_OBJ_FLOAT || obj_type == MP_PERSISTENT_OBJ_COMPLEX); - return mp_parse_num_float(vstr.buf, vstr.len, obj_type == MP_PERSISTENT_OBJ_COMPLEX, NULL); + return mp_obj_new_bytes_from_vstr(&vstr); } } } @@ -488,6 +571,23 @@ STATIC void save_qstr(mp_print_t *print, qstr qst) { mp_print_bytes(print, str, len + 1); // +1 to store null terminator } +#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE +STATIC void mp_print_float_binary(mp_print_t *print, mp_float_t f) { + mp_float_union_t fu = { .f = f }; + mp_float_uint_t f_int_val = fu.i; + + #if MP_ENDIANNESS_LITTLE + mp_print_bytes(print, (const byte *)&f_int_val, sizeof(f_int_val)); + #else + for (int i = 0; i < sizeof(f_int_val); i++) { + const byte b = f_int_val & 0xff; + mp_print_bytes(print, &b, 1); + f_int_val >>= 8; + } + #endif +} +#endif + STATIC void save_obj(mp_print_t *print, mp_obj_t o) { #if MICROPY_EMIT_MACHINE_CODE if (o == MP_OBJ_FROM_PTR(&mp_fun_table)) { @@ -529,29 +629,91 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { for (size_t i = 0; i < len; ++i) { save_obj(print, items[i]); } - } else { - // we save numbers using a simplistic text representation - // TODO could be improved - byte obj_type; - if (mp_obj_is_int(o)) { - obj_type = MP_PERSISTENT_OBJ_INT; - #if MICROPY_PY_BUILTINS_COMPLEX - } else if (mp_obj_is_type(o, &mp_type_complex)) { - obj_type = MP_PERSISTENT_OBJ_COMPLEX; - #endif + } else if (mp_obj_is_int(o)) { + // Integers are saved as a metadata byte followed by the little-endian bytes of the integer. + // The metadata is the length shifted left by one, ORed with a bit specifying whether the + // integer is negative (1) or positive (0). + vstr_t vstr = {0}; + byte smallint_buf[sizeof(mp_int_t)]; + + size_t len; + byte *buf; + bool is_negative = mp_obj_int_sign(o) == -1; + + if (mp_obj_is_small_int(o)) { + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o); + + len = sizeof(mp_int_t); + mp_binary_set_int(len, false, smallint_buf, val); + buf = smallint_buf; } else { - assert(mp_obj_is_float(o)); - obj_type = MP_PERSISTENT_OBJ_FLOAT; + len = mp_obj_int_max_bytes_needed_impl(o); + vstr_init(&vstr, len); + mp_obj_int_to_bytes_impl(o, false, len, (byte *)vstr.buf); + buf = (byte *)vstr.buf; } - vstr_t vstr; - mp_print_t pr; - vstr_init_print(&vstr, 10, &pr); - mp_obj_print_helper(&pr, o, PRINT_REPR); + + // Try to chop off as many bytes as possible (starting from MSB). Either chop off 0xff + // bytes if the resulting number's MSB is still 1 (is_negative=true), or chop off zero + // bytes (is_negative=false) + size_t leading_unneeded_bytes = 0; + for (int i = len - 1; i >= 0; i--) { + if (is_negative) { + // Try to remove a 0xff byte + if (i > 0 && buf[i] == 0xff && buf[i - 1] & 0x80) { + // The current byte is all 1s, and the MSB of the next byte is 1, so this + // byte can be chopped off. + leading_unneeded_bytes++; + } else { + // byte is required, end. + break; + } + } else if (buf[i] == 0) { + // Remove a zero byte + leading_unneeded_bytes++; + } else { + // byte is required, end. + break; + } + } + len -= leading_unneeded_bytes; + + byte obj_type = MP_PERSISTENT_OBJ_INT; mp_print_bytes(print, &obj_type, 1); - mp_print_uint(print, vstr.len); - mp_print_bytes(print, (const byte *)vstr.buf, vstr.len); + mp_print_uint(print, (len << 1) | is_negative); + mp_print_bytes(print, buf, len); + vstr_clear(&vstr); } + #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE + #if MICROPY_PY_BUILTINS_COMPLEX + else if (mp_obj_is_type(o, &mp_type_complex)) { + mp_float_t real, imag; + mp_obj_complex_get(o, &real, &imag); + + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + byte obj_type = MP_PERSISTENT_OBJ_COMPLEX_DOUBLE; + #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + byte obj_type = MP_PERSISTENT_OBJ_COMPLEX_FLOAT; + #endif + mp_print_bytes(print, &obj_type, 1); + mp_print_float_binary(print, real); + mp_print_float_binary(print, imag); + } + #endif + else if (mp_obj_is_float(o)) { + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + byte obj_type = MP_PERSISTENT_OBJ_FP_DOUBLE; + #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + byte obj_type = MP_PERSISTENT_OBJ_FP_FLOAT; + #endif + mp_print_bytes(print, &obj_type, 1); + mp_print_float_binary(print, mp_obj_float_get(o)); + } + #endif + else { + mp_raise_ValueError(MP_ERROR_TEXT("Unhandled constant type")); + } } STATIC void save_raw_code(mp_print_t *print, const mp_raw_code_t *rc) { diff --git a/py/persistentcode.h b/py/persistentcode.h index d363f544ad558..1241d9a4a48c0 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -34,7 +34,7 @@ // as long as MPY_VERSION matches, but a native .mpy (i.e. one with an arch // set) must also match MPY_SUB_VERSION. This allows 3 additional updates to // the native ABI per bytecode revision. -#define MPY_VERSION 6 +#define MPY_VERSION 7 #define MPY_SUB_VERSION 1 // Macros to encode/decode sub-version to/from the feature byte. This replaces @@ -106,8 +106,10 @@ enum { MP_PERSISTENT_OBJ_STR, MP_PERSISTENT_OBJ_BYTES, MP_PERSISTENT_OBJ_INT, - MP_PERSISTENT_OBJ_FLOAT, - MP_PERSISTENT_OBJ_COMPLEX, + MP_PERSISTENT_OBJ_FP_FLOAT, + MP_PERSISTENT_OBJ_FP_DOUBLE, + MP_PERSISTENT_OBJ_COMPLEX_FLOAT, + MP_PERSISTENT_OBJ_COMPLEX_DOUBLE, MP_PERSISTENT_OBJ_TUPLE, }; diff --git a/tests/frozen/frozentest.mpy b/tests/frozen/frozentest.mpy index 99581617ac3d1..06fee65c285cd 100644 Binary files a/tests/frozen/frozentest.mpy and b/tests/frozen/frozentest.mpy differ diff --git a/tests/micropython/import_mpy_native.py b/tests/micropython/import_mpy_native.py index da20746b225de..94cbf3ae8a535 100644 --- a/tests/micropython/import_mpy_native.py +++ b/tests/micropython/import_mpy_native.py @@ -52,11 +52,11 @@ def open(self, path, mode): # these are the test .mpy files -valid_header = bytes([77, 6, mpy_arch, 31]) +valid_header = bytes([77, 7, mpy_arch, 31]) # fmt: off user_files = { # bad architecture (mpy_arch needed for sub-version) - '/mod0.mpy': bytes([77, 6, 0xfc | mpy_arch, 31]), + '/mod0.mpy': bytes([77, 7, 0xfc | mpy_arch, 31]), # test loading of viper and asm '/mod1.mpy': valid_header + ( diff --git a/tests/perf_bench/core_import_mpy_multi.py b/tests/perf_bench/core_import_mpy_multi.py index 364c325042843..950bec7e4d271 100644 --- a/tests/perf_bench/core_import_mpy_multi.py +++ b/tests/perf_bench/core_import_mpy_multi.py @@ -23,7 +23,7 @@ def f(): x = ("const tuple", None, False, True, 1, 2, 3) result = 123 """ -file_data = b'M\x06\x00\x1f\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00\x0cresult\x00/-5#\x82I\x81{\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x06arg\x00\x05\x1cthis will be a string object\x00\x06\x1bthis will be a bytes object\x00\n\x07\x05\x0bconst tuple\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x04Qc\x02\x81d\x00\x08\x02(DD\x11\x05\x16\x06\x10\x02\x16\x072\x00\x16\x082\x01\x16\t2\x02\x16\nQc\x03`\x1a\x08\x08\x12\x13@\xb1\xb0\x18\x13Qc@\t\x08\t\x12` Qc@\t\x08\n\x12``Qc\x82@ \x0e\x03\x80\x08+)##\x12\x0b\x12\x0c\x12\r\x12\x0e*\x04Y\x12\x0f\x12\x10\x12\x11*\x03Y#\x00\xc0#\x01\xc0#\x02\xc0Qc' +file_data = b'M\x07\x00\x1f\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00#\x06arg\x00\x82I\x81{\x0cresult\x00/-5\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x05\x1cthis will be a string object\x00\x06\x1bthis will be a bytes object\x00\x0c\x07\x05\x0bconst tuple\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x08Qc\x02\x81d\x00\x08\x02(DD\x11\t\x16\n\x10\x02\x16\x0b2\x00\x16\x042\x01\x16\x062\x02\x16\x07Qc\x03`\x1a\x08\x04\x13\x05@\xb1\xb0\x18\x05Qc@\t\x08\x06\x13` Qc@\t\x08\x07\x13``Qc\x82@ \x0e\x03\x80\x08+)##\x12\x0c\x12\r\x12\x0e\x12\x0f*\x04Y\x12\x10\x12\x11\x12\x12*\x03Y#\x00\xc0#\x01\xc0#\x02\xc0Qc' class File(io.IOBase): diff --git a/tests/perf_bench/core_import_mpy_single.py b/tests/perf_bench/core_import_mpy_single.py index 5757c3eaf1fdf..2454bd693eaa8 100644 --- a/tests/perf_bench/core_import_mpy_single.py +++ b/tests/perf_bench/core_import_mpy_single.py @@ -78,7 +78,7 @@ def f1(): x = ("const tuple 9", None, False, True, 1, 2, 3) result = 123 """ -file_data = b"M\x06\x00\x1f\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x0cresult\x00/-5\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00\x05\x1ethis will be a string object 0\x00\x05\x1ethis will be a string object 1\x00\x05\x1ethis will be a string object 2\x00\x05\x1ethis will be a string object 3\x00\x05\x1ethis will be a string object 4\x00\x05\x1ethis will be a string object 5\x00\x05\x1ethis will be a string object 6\x00\x05\x1ethis will be a string object 7\x00\x05\x1ethis will be a string object 8\x00\x05\x1ethis will be a string object 9\x00\x06\x1dthis will be a bytes object 0\x00\x06\x1dthis will be a bytes object 1\x00\x06\x1dthis will be a bytes object 2\x00\x06\x1dthis will be a bytes object 3\x00\x06\x1dthis will be a bytes object 4\x00\x06\x1dthis will be a bytes object 5\x00\x06\x1dthis will be a bytes object 6\x00\x06\x1dthis will be a bytes object 7\x00\x06\x1dthis will be a bytes object 8\x00\x06\x1dthis will be a bytes object 9\x00\n\x07\x05\rconst tuple 0\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 1\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 2\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 3\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 4\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 5\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 6\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 7\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 8\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 9\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\x06Qc\x04\x82\x0c\x00\n\x02($$$\x11\x07\x16\x08\x10\x02\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04@\t\x08\n\x81\x0b Qc@\t\x08\x0b\x81\x0b@Qc@\t\x08\x0c\x81\x0b`QcH\t\n\r\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x07\x16\x08\x10\x03\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04H\t\n\n\x81\x0b``QcH\t\n\x0b\x81\x0b\x80\x07QcH\t\n\x0c\x81\x0b\x80\x08QcH\t\n\r\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x08\x12\x07*\x08Y\x12\x1b\x12\x1c\x12\t\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x87p\x08@\x05\x80###############################\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14\xc0#\x15\xc0#\x16\xc0#\x17\xc0#\x18\xc0#\x19\xc0#\x1a\xc0#\x1b\xc0#\x1c\xc0#\x1d\xc0Qc" +file_data = b"M\x07\x00\x1f\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x0cresult\x00/-5\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00\x05\x1ethis will be a string object 0\x00\x05\x1ethis will be a string object 1\x00\x05\x1ethis will be a string object 2\x00\x05\x1ethis will be a string object 3\x00\x05\x1ethis will be a string object 4\x00\x05\x1ethis will be a string object 5\x00\x05\x1ethis will be a string object 6\x00\x05\x1ethis will be a string object 7\x00\x05\x1ethis will be a string object 8\x00\x05\x1ethis will be a string object 9\x00\x06\x1dthis will be a bytes object 0\x00\x06\x1dthis will be a bytes object 1\x00\x06\x1dthis will be a bytes object 2\x00\x06\x1dthis will be a bytes object 3\x00\x06\x1dthis will be a bytes object 4\x00\x06\x1dthis will be a bytes object 5\x00\x06\x1dthis will be a bytes object 6\x00\x06\x1dthis will be a bytes object 7\x00\x06\x1dthis will be a bytes object 8\x00\x06\x1dthis will be a bytes object 9\x00\x0c\x07\x05\rconst tuple 0\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 1\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 2\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 3\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 4\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 5\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 6\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 7\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 8\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x0c\x07\x05\rconst tuple 9\x00\x01\x02\x03\x07\x02\x01\x07\x02\x02\x07\x02\x03\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\nQc\x04\x82\x0c\x00\n\x02($$$\x11\x0b\x16\x0c\x10\x02\x16\r2\x00\x16\x062\x01\x16\x072\x02\x16\x082\x03\x16\tQc\x04@\t\x08\x06\x81\x0b Qc@\t\x08\x07\x81\x0b@Qc@\t\x08\x08\x81\x0b`QcH\t\n\t\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x0b\x16\x0c\x10\x03\x16\r2\x00\x16\x062\x01\x16\x072\x02\x16\x082\x03\x16\tQc\x04H\t\n\x06\x81\x0b``QcH\t\n\x07\x81\x0b\x80\x07QcH\t\n\x08\x81\x0b\x80\x08QcH\t\n\t\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x0c\x12\x0b*\x08Y\x12\x1b\x12\x1c\x12\r\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x87p\x08@\x05\x80###############################\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14\xc0#\x15\xc0#\x16\xc0#\x17\xc0#\x18\xc0#\x19\xc0#\x1a\xc0#\x1b\xc0#\x1c\xc0#\x1d\xc0Qc" class File(io.IOBase): diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 7f581d0b1345c..4edcebf0e4d94 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -87,7 +87,7 @@ def __str__(self): class Config: - MPY_VERSION = 6 + MPY_VERSION = 7 MPY_SUB_VERSION = 1 MICROPY_LONGINT_IMPL_NONE = 0 MICROPY_LONGINT_IMPL_LONGLONG = 1 @@ -122,9 +122,11 @@ class Config: MP_PERSISTENT_OBJ_STR = 5 MP_PERSISTENT_OBJ_BYTES = 6 MP_PERSISTENT_OBJ_INT = 7 -MP_PERSISTENT_OBJ_FLOAT = 8 -MP_PERSISTENT_OBJ_COMPLEX = 9 -MP_PERSISTENT_OBJ_TUPLE = 10 +MP_PERSISTENT_OBJ_FP_FLOAT = 8 +MP_PERSISTENT_OBJ_FP_DOUBLE = 9 +MP_PERSISTENT_OBJ_COMPLEX_FLOAT = 10 +MP_PERSISTENT_OBJ_COMPLEX_DOUBLE = 11 +MP_PERSISTENT_OBJ_TUPLE = 12 MP_SCOPE_FLAG_VIPERRELOC = 0x10 MP_SCOPE_FLAG_VIPERRODATA = 0x20 @@ -1206,7 +1208,11 @@ def read_qstr(reader, segments): def read_obj(reader, segments): + def append_seg(obj): + segments.append(MPYSegment(MPYSegment.OBJ, obj, start_pos, reader.tell())) + obj_type = reader.read_byte() + start_pos = reader.tell() if obj_type == MP_PERSISTENT_OBJ_FUN_TABLE: return MPFunTable() elif obj_type == MP_PERSISTENT_OBJ_NONE: @@ -1220,6 +1226,35 @@ def read_obj(reader, segments): elif obj_type == MP_PERSISTENT_OBJ_TUPLE: ln = reader.read_uint() return tuple(read_obj(reader, segments) for _ in range(ln)) + elif obj_type == MP_PERSISTENT_OBJ_INT: + ln_neg = reader.read_uint() + ln = ln_neg >> 1 + is_negative = ln_neg & 1 + + start_pos = reader.tell() + obj = int.from_bytes(reader.read_bytes(ln), byteorder="little", signed=is_negative) + append_seg(obj) + return obj + elif obj_type == MP_PERSISTENT_OBJ_FP_FLOAT: + (obj,) = struct.unpack(" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy