diff --git a/py/compile.c b/py/compile.c index 6fffd9c0bf..5c2fce6866 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2439,7 +2439,12 @@ STATIC void compile_bytes(compiler_t *comp, mp_parse_node_struct_t *pns) { } STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) { + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // nodes are 32-bit pointers, but need to extract 64-bit object + EMIT_ARG(load_const_obj, (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32)); + #else EMIT_ARG(load_const_obj, (mp_obj_t)pns->nodes[0]); + #endif } typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*); diff --git a/py/mpconfig.h b/py/mpconfig.h index 01956f63f7..1f01b3de55 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -76,6 +76,19 @@ #define MICROPY_OBJ_REPR_C (2) +// A MicroPython object is a 64-bit word having the following form (called R): +// - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff +// - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf +// - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan +// - 01111111 11111101 00000000 00000000 iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int +// - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str +// - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) +// Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000. +// This makes pointers have all zeros in the top 32 bits. +// Small-ints and strs have 1 as LSB to make sure they don't look like pointers +// to the garbage collector. +#define MICROPY_OBJ_REPR_D (3) + #ifndef MICROPY_OBJ_REPR #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) #endif diff --git a/py/obj.h b/py/obj.h index 09c8eda646..174b89ee92 100644 --- a/py/obj.h +++ b/py/obj.h @@ -32,10 +32,15 @@ #include "py/mpprint.h" // All Micro Python objects are at least this type -// It must be of pointer size +// The bit-size must be at least pointer size +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +typedef uint64_t mp_obj_t; +typedef uint64_t mp_const_obj_t; +#else typedef machine_ptr_t mp_obj_t; typedef machine_const_ptr_t mp_const_obj_t; +#endif // Anything that wants to be a Micro Python object must have // mp_obj_base_t as its first member (except small ints and qstrs) @@ -158,6 +163,56 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + +static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0001000000000000); } +#define MP_OBJ_SMALL_INT_VALUE(o) (((intptr_t)(o)) >> 1) +#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((uintptr_t)(small_int)) << 1) | 0x0001000000000001) + +static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } +#define MP_OBJ_QSTR_VALUE(o) ((((mp_uint_t)(o)) >> 1) & 0xffffffff) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) + +#if MICROPY_PY_BUILTINS_FLOAT +#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b125769 + 0x8004000000000000))} +#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} + +static inline bool mp_obj_is_float(mp_const_obj_t o) { + return ((uint64_t)(o) & 0xfffc000000000000) != 0; +} +static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { + union { + mp_float_t f; + uint64_t r; + } num = {.r = o - 0x8004000000000000}; + return num.f; +} +static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + union { + mp_float_t f; + uint64_t r; + } num = {.f = f}; + return num.r + 0x8004000000000000; +} +#endif + +static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) + { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000); } +#define MP_OBJ_TO_PTR(o) ((void*)(uintptr_t)(o)) +#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)((uintptr_t)(p))) + +// rom object storage needs special handling to widen 32-bit pointer to 64-bits +typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; } mp_rom_obj_t; +#define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)} +#define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)} +#if MP_ENDIANNESS_LITTLE +#define MP_ROM_PTR(p) {.u32 = {.lo = (p), .hi = NULL}} +#else +#define MP_ROM_PTR(p) {.u32 = {.lo = NULL, .hi = (p)}} +#endif + #endif // Macros to convert between mp_obj_t and concrete object types. diff --git a/py/objfloat.c b/py/objfloat.c index c9e3ddd376..051c0f61c3 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -39,7 +39,7 @@ #include #include "py/formatfloat.h" -#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C +#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D typedef struct _mp_obj_float_t { mp_obj_base_t base; @@ -125,7 +125,7 @@ const mp_obj_type_t mp_type_float = { .binary_op = float_binary_op, }; -#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C +#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D mp_obj_t mp_obj_new_float(mp_float_t value) { mp_obj_float_t *o = m_new(mp_obj_float_t, 1); diff --git a/py/parse.c b/py/parse.c index afe8711a2d..25aeeae03b 100644 --- a/py/parse.c +++ b/py/parse.c @@ -283,7 +283,11 @@ void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent) { } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_bytes) { printf("literal bytes(%.*s)\n", (int)pns->nodes[1], (char*)pns->nodes[0]); } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) { + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + printf("literal const(%016llx)\n", (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32)); + #else printf("literal const(%p)\n", (mp_obj_t)pns->nodes[0]); + #endif } else { mp_uint_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); #ifdef USE_RULE_NAME @@ -362,8 +366,15 @@ STATIC mp_parse_node_t make_node_const_object(parser_t *parser, mp_uint_t src_li return MP_PARSE_NODE_NULL; } pn->source_line = src_line; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // nodes are 32-bit pointers, but need to store 64-bit object + pn->kind_num_nodes = RULE_const_object | (2 << 8); + pn->nodes[0] = (uint64_t)obj; + pn->nodes[1] = (uint64_t)obj >> 32; + #else pn->kind_num_nodes = RULE_const_object | (1 << 8); pn->nodes[0] = (mp_uint_t)obj; + #endif return (mp_parse_node_t)pn; } diff --git a/py/smallint.h b/py/smallint.h index d9e53ee361..0e30a80856 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -46,6 +46,13 @@ // Mask to truncate mp_int_t to positive value #define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1) | (WORD_MSBIT_HIGH >> 2)) +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffffffff80000000) >> 1)) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffffffff80000000) == 0) +// Mask to truncate mp_int_t to positive value +#define MP_SMALL_INT_POSITIVE_MASK ~(0xffffffff80000000 | (0xffffffff80000000 >> 1)) + #endif #define MP_SMALL_INT_MAX ((mp_int_t)(~(MP_SMALL_INT_MIN)))