Skip to content

Commit 3ac8b58

Browse files
jimmodpgeorge
authored andcommitted
py/obj: Add slot-index mp_obj_type_t representation.
The existings mp_obj_type_t uses a sparse representation for slots for the capability methods of the type (eg print, make_new). This commit adds a compact slot-index representation. The basic idea is that where the mp_obj_type_t struct used to have 12 pointer fields, it now has 12 uint8_t indices, and a variable-length array of pointers. So in the best case (no fields used) it saves 12x4-12=36 bytes (on a 32-bit machine) and in the common case (three fields used) it saves 9x4-12=24 bytes. Overall with all associated changes, this slot-index representation reduces code size by 1000 to 3000 bytes on bare-metal ports. Performance is marginally better on a few tests (eg about 1% better on misc_pystone.py and misc_raytrace.py on PYBv1.1), but overall marginally worse by a percent or so. See issue #7542 for further analysis and discussion. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent a52cd5b commit 3ac8b58

File tree

2 files changed

+125
-3
lines changed

2 files changed

+125
-3
lines changed

py/mpconfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@
145145
#define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D)
146146
#endif
147147

148+
#define MICROPY_OBJ_TYPE_REPR_FULL (0)
149+
#define MICROPY_OBJ_TYPE_REPR_SLOT_INDEX (1)
150+
151+
#ifndef MICROPY_OBJ_TYPE_REPR
152+
#define MICROPY_OBJ_TYPE_REPR (MICROPY_OBJ_TYPE_REPR_FULL)
153+
#endif
154+
148155
/*****************************************************************************/
149156
/* Memory allocation policy */
150157

py/obj.h

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,12 +575,13 @@ struct _mp_obj_type_t {
575575
// The name of this type, a qstr.
576576
uint16_t name;
577577

578-
// Corresponds to __repr__ and __str__ special methods.
579-
mp_print_fun_t print;
580-
581578
// Corresponds to __new__ and __init__ special methods, to make an instance of the type.
582579
mp_make_new_fun_t make_new;
583580

581+
#if MICROPY_OBJ_TYPE_REPR == MICROPY_OBJ_TYPE_REPR_FULL
582+
// Corresponds to __repr__ and __str__ special methods.
583+
mp_print_fun_t print;
584+
584585
// Corresponds to __call__ special method, ie T(...).
585586
mp_call_fun_t call;
586587

@@ -633,17 +634,87 @@ struct _mp_obj_type_t {
633634

634635
// A dict mapping qstrs to objects local methods/constants/etc.
635636
struct _mp_obj_dict_t *locals_dict;
637+
638+
#elif MICROPY_OBJ_TYPE_REPR == MICROPY_OBJ_TYPE_REPR_SLOT_INDEX
639+
640+
// Ideally these would be only 4 bits, but the extra overhead of
641+
// accessing them adds more code, and we also need to be able to
642+
// take the address of them for mp_obj_class_lookup.
643+
uint8_t slot_index_print;
644+
uint8_t slot_index_call;
645+
uint8_t slot_index_unary_op;
646+
uint8_t slot_index_binary_op;
647+
uint8_t slot_index_attr;
648+
uint8_t slot_index_subscr;
649+
uint8_t slot_index_getiter;
650+
uint8_t slot_index_iternext;
651+
uint8_t slot_index_buffer;
652+
uint8_t slot_index_protocol;
653+
uint8_t slot_index_parent;
654+
uint8_t slot_index_locals_dict;
655+
656+
const void *slots[];
657+
658+
#endif
636659
};
637660

638661
// Non-variable sized versions of mp_obj_type_t to be used as a member
639662
// in other structs or for dynamic allocation. The fields are exactly
640663
// as in mp_obj_type_t, but with a fixed size for the flexible array
641664
// members.
665+
#if MICROPY_OBJ_TYPE_REPR == MICROPY_OBJ_TYPE_REPR_FULL
642666
typedef mp_obj_type_t mp_obj_empty_type_t;
643667
typedef mp_obj_type_t mp_obj_full_type_t;
668+
#else
669+
typedef struct _mp_obj_empty_type_t {
670+
mp_obj_base_t base;
671+
uint16_t flags;
672+
uint16_t name;
673+
mp_make_new_fun_t make_new;
674+
675+
uint8_t slot_index_print;
676+
uint8_t slot_index_call;
677+
uint8_t slot_index_unary_op;
678+
uint8_t slot_index_binary_op;
679+
uint8_t slot_index_attr;
680+
uint8_t slot_index_subscr;
681+
uint8_t slot_index_getiter;
682+
uint8_t slot_index_iternext;
683+
uint8_t slot_index_buffer;
684+
uint8_t slot_index_protocol;
685+
uint8_t slot_index_parent;
686+
uint8_t slot_index_locals_dict;
687+
688+
// No slots member.
689+
} mp_obj_empty_type_t;
690+
691+
typedef struct _mp_obj_full_type_t {
692+
mp_obj_base_t base;
693+
uint16_t flags;
694+
uint16_t name;
695+
mp_make_new_fun_t make_new;
696+
697+
uint8_t slot_index_print;
698+
uint8_t slot_index_call;
699+
uint8_t slot_index_unary_op;
700+
uint8_t slot_index_binary_op;
701+
uint8_t slot_index_attr;
702+
uint8_t slot_index_subscr;
703+
uint8_t slot_index_getiter;
704+
uint8_t slot_index_iternext;
705+
uint8_t slot_index_buffer;
706+
uint8_t slot_index_protocol;
707+
uint8_t slot_index_parent;
708+
uint8_t slot_index_locals_dict;
709+
710+
// Explicitly add 12 slots.
711+
const void *slots[12];
712+
} mp_obj_full_type_t;
713+
#endif
644714

645715
#define MP_TYPE_NULL_MAKE_NEW (NULL)
646716

717+
#if MICROPY_OBJ_TYPE_REPR == MICROPY_OBJ_TYPE_REPR_FULL
647718
// Implementation of MP_DEFINE_CONST_OBJ_TYPE for each number of arguments.
648719
// Do not use these directly, instead use MP_DEFINE_CONST_OBJ_TYPE.
649720
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_0(_struct_type, _typename, _name, _flags, _make_new) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new }
@@ -670,6 +741,50 @@ typedef mp_obj_type_t mp_obj_full_type_t;
670741
#define MP_OBJ_TYPE_OFFSETOF_SLOT(f) (offsetof(mp_obj_type_t, f))
671742
#define MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(t, offset) (*(void **)((char *)(t) + (offset)) != NULL)
672743

744+
#elif MICROPY_OBJ_TYPE_REPR == MICROPY_OBJ_TYPE_REPR_SLOT_INDEX
745+
746+
#define _MP_OBJ_TYPE_SLOT_TYPE_print (mp_print_fun_t)
747+
#define _MP_OBJ_TYPE_SLOT_TYPE_call (mp_call_fun_t)
748+
#define _MP_OBJ_TYPE_SLOT_TYPE_unary_op (mp_unary_op_fun_t)
749+
#define _MP_OBJ_TYPE_SLOT_TYPE_binary_op (mp_binary_op_fun_t)
750+
#define _MP_OBJ_TYPE_SLOT_TYPE_attr (mp_attr_fun_t)
751+
#define _MP_OBJ_TYPE_SLOT_TYPE_subscr (mp_subscr_fun_t)
752+
#define _MP_OBJ_TYPE_SLOT_TYPE_getiter (mp_getiter_fun_t)
753+
#define _MP_OBJ_TYPE_SLOT_TYPE_iternext (mp_fun_1_t)
754+
#define _MP_OBJ_TYPE_SLOT_TYPE_buffer (mp_buffer_fun_t)
755+
#define _MP_OBJ_TYPE_SLOT_TYPE_protocol (const void *)
756+
#define _MP_OBJ_TYPE_SLOT_TYPE_parent (const void *)
757+
#define _MP_OBJ_TYPE_SLOT_TYPE_locals_dict (struct _mp_obj_dict_t *)
758+
759+
// Implementation of MP_DEFINE_CONST_OBJ_TYPE for each number of arguments.
760+
// Do not use these directly, instead use MP_DEFINE_CONST_OBJ_TYPE.
761+
// Generated with:
762+
// for i in range(13):
763+
// print(f"#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_{i}(_struct_type, _typename, _name, _flags, _make_new{''.join(f', f{j+1}, v{j+1}' for j in range(i))}) const _struct_type _typename = {{ .base = {{ &mp_type_type }}, .name = _name, .flags = _flags, .make_new = _make_new{''.join(f', .slot_index_##f{j+1} = {j+1}' for j in range(i))}{', .slots = { ' + ''.join(f'v{j+1}, ' for j in range(i)) + '}' if i else '' } }}")
764+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_0(_struct_type, _typename, _name, _flags, _make_new) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new }
765+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_1(_struct_type, _typename, _name, _flags, _make_new, f1, v1) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slots = { v1, } }
766+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_2(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slots = { v1, v2, } }
767+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_3(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slots = { v1, v2, v3, } }
768+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_4(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slots = { v1, v2, v3, v4, } }
769+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_5(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slots = { v1, v2, v3, v4, v5, } }
770+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_6(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slots = { v1, v2, v3, v4, v5, v6, } }
771+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_7(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slots = { v1, v2, v3, v4, v5, v6, v7, } }
772+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_8(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, } }
773+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_9(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, } }
774+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_10(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, } }
775+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_11(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slot_index_##f11 = 11, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, } }
776+
#define MP_DEFINE_CONST_OBJ_TYPE_NARGS_12(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11, f12, v12) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .slot_index_##f1 = 1, .slot_index_##f2 = 2, .slot_index_##f3 = 3, .slot_index_##f4 = 4, .slot_index_##f5 = 5, .slot_index_##f6 = 6, .slot_index_##f7 = 7, .slot_index_##f8 = 8, .slot_index_##f9 = 9, .slot_index_##f10 = 10, .slot_index_##f11 = 11, .slot_index_##f12 = 12, .slots = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, } }
777+
778+
#define MP_OBJ_TYPE_HAS_SLOT(t, f) ((t)->slot_index_##f)
779+
#define MP_OBJ_TYPE_GET_SLOT(t, f) (_MP_OBJ_TYPE_SLOT_TYPE_##f(t)->slots[(t)->slot_index_##f - 1])
780+
#define MP_OBJ_TYPE_GET_SLOT_OR_NULL(t, f) (_MP_OBJ_TYPE_SLOT_TYPE_##f(MP_OBJ_TYPE_HAS_SLOT(t, f) ? MP_OBJ_TYPE_GET_SLOT(t, f) : NULL))
781+
#define MP_OBJ_TYPE_SET_SLOT(t, f, v, n) ((t)->slot_index_##f = (n) + 1, (t)->slots[(t)->slot_index_##f - 1] = (void *)v)
782+
#define MP_OBJ_TYPE_OFFSETOF_SLOT(f) (offsetof(mp_obj_type_t, slot_index_##f))
783+
// For everything except make_new, the offset is to the uint8_t index. For make_new, we need to check the pointer.
784+
#define MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(t, offset) (*(uint8_t *)((char *)(t) + (offset)) != 0 || (offset == offsetof(mp_obj_type_t, make_new) && t->make_new))
785+
786+
#endif
787+
673788
// Workaround for https://docs.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-160#macro-arguments-are-unpacked
674789
#define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x
675790

0 commit comments

Comments
 (0)
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