py/obj: Add MICROPY_OBJ_IMMEDIATE_OBJS option to reduce code size.

This option (enabled by default for object representation A, B, C) makes
None/False/True objects immediate objects, ie they are no longer a concrete
object in ROM but are rather just values, eg None=0x6 for representation A.

Doing this saves a considerable amount of code size, due to these objects
being widely used:

   bare-arm:  -392 -0.591%
minimal x86:  -252 -0.170% [incl +52(data)]
   unix x64:  -624 -0.125% [incl -128(data)]
unix nanbox:    +0 +0.000%
      stm32: -1940 -0.510% PYBV10
     cc3200: -1216 -0.659%
    esp8266:  -404 -0.062% GENERIC
      esp32:  -732 -0.064% GENERIC[incl +48(data)]
        nrf:  -988 -0.675% pca10040
       samd:  -564 -0.556% ADAFRUIT_ITSYBITSY_M4_EXPRESS

Thanks go to @Jongy aka Yonatan Goldschmidt for the idea.
This commit is contained in:
Damien George 2020-01-09 00:00:27 +11:00
parent 6f0c83f6e1
commit d96cfd13e3
5 changed files with 59 additions and 12 deletions

View File

@ -113,6 +113,13 @@
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
#endif #endif
// Whether to encode None/False/True as immediate objects instead of pointers to
// real objects. Reduces code size by a decent amount without hurting
// performance, for all representations except D on some architectures.
#ifndef MICROPY_OBJ_IMMEDIATE_OBJS
#define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D)
#endif
/*****************************************************************************/ /*****************************************************************************/
/* Memory allocation policy */ /* Memory allocation policy */

View File

@ -46,6 +46,11 @@ const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
} else if (mp_obj_is_float(o_in)) { } else if (mp_obj_is_float(o_in)) {
return &mp_type_float; return &mp_type_float;
#endif #endif
#if MICROPY_OBJ_IMMEDIATE_OBJS
} else if (mp_obj_is_immediate_obj(o_in)) {
static const mp_obj_type_t *const types[2] = {&mp_type_NoneType, &mp_type_bool};
return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1];
#endif
} else { } else {
const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
return o->type; return o->type;

View File

@ -263,13 +263,22 @@ typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32;
// Macros to create objects that are stored in ROM. // Macros to create objects that are stored in ROM.
#ifndef MP_ROM_NONE #ifndef MP_ROM_NONE
#if MICROPY_OBJ_IMMEDIATE_OBJS
#define MP_ROM_NONE mp_const_none
#else
#define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj) #define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj)
#endif #endif
#endif
#ifndef MP_ROM_FALSE #ifndef MP_ROM_FALSE
#if MICROPY_OBJ_IMMEDIATE_OBJS
#define MP_ROM_FALSE mp_const_false
#define MP_ROM_TRUE mp_const_true
#else
#define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj) #define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj)
#define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj) #define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj)
#endif #endif
#endif
#ifndef MP_ROM_INT #ifndef MP_ROM_INT
typedef mp_const_obj_t mp_rom_obj_t; typedef mp_const_obj_t mp_rom_obj_t;
@ -622,17 +631,27 @@ extern const mp_obj_type_t mp_type_ValueError;
extern const mp_obj_type_t mp_type_ViperTypeError; extern const mp_obj_type_t mp_type_ViperTypeError;
extern const mp_obj_type_t mp_type_ZeroDivisionError; extern const mp_obj_type_t mp_type_ZeroDivisionError;
// Constant objects, globally accessible // Constant objects, globally accessible: None, False, True
// The macros are for convenience only // These should always be accessed via the below macros.
#if MICROPY_OBJ_IMMEDIATE_OBJS
// None is even while False/True are odd so their types can be distinguished with 1 bit.
#define mp_const_none MP_OBJ_NEW_IMMEDIATE_OBJ(0)
#define mp_const_false MP_OBJ_NEW_IMMEDIATE_OBJ(1)
#define mp_const_true MP_OBJ_NEW_IMMEDIATE_OBJ(3)
#else
#define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj)) #define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj))
#define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj)) #define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj))
#define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj)) #define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj))
#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))
extern const struct _mp_obj_none_t mp_const_none_obj; extern const struct _mp_obj_none_t mp_const_none_obj;
extern const struct _mp_obj_bool_t mp_const_false_obj; extern const struct _mp_obj_bool_t mp_const_false_obj;
extern const struct _mp_obj_bool_t mp_const_true_obj; extern const struct _mp_obj_bool_t mp_const_true_obj;
#endif
// Constant objects, globally accessible: b'', (), Ellipsis, NotImplemented, GeneratorExit()
// The below macros are for convenience only.
#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))
extern const struct _mp_obj_str_t mp_const_empty_bytes_obj; extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj; extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj; extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;

View File

@ -28,21 +28,31 @@
#include "py/runtime.h" #include "py/runtime.h"
#if MICROPY_OBJ_IMMEDIATE_OBJS
#define BOOL_VALUE(o) ((o) == mp_const_false ? 0 : 1)
#else
#define BOOL_VALUE(o) (((mp_obj_bool_t*)MP_OBJ_TO_PTR(o))->value)
typedef struct _mp_obj_bool_t { typedef struct _mp_obj_bool_t {
mp_obj_base_t base; mp_obj_base_t base;
bool value; bool value;
} mp_obj_bool_t; } mp_obj_bool_t;
#endif
STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_bool_t *self = MP_OBJ_TO_PTR(self_in); bool value = BOOL_VALUE(self_in);
if (MICROPY_PY_UJSON && kind == PRINT_JSON) { if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
if (self->value) { if (value) {
mp_print_str(print, "true"); mp_print_str(print, "true");
} else { } else {
mp_print_str(print, "false"); mp_print_str(print, "false");
} }
} else { } else {
if (self->value) { if (value) {
mp_print_str(print, "True"); mp_print_str(print, "True");
} else { } else {
mp_print_str(print, "False"); mp_print_str(print, "False");
@ -65,13 +75,13 @@ STATIC mp_obj_t bool_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
if (op == MP_UNARY_OP_LEN) { if (op == MP_UNARY_OP_LEN) {
return MP_OBJ_NULL; return MP_OBJ_NULL;
} }
mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in); bool value = BOOL_VALUE(o_in);
return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value)); return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(value));
} }
STATIC mp_obj_t bool_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { STATIC mp_obj_t bool_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_bool_t *self = MP_OBJ_TO_PTR(lhs_in); bool value = BOOL_VALUE(lhs_in);
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(self->value), rhs_in); return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(value), rhs_in);
} }
const mp_obj_type_t mp_type_bool = { const mp_obj_type_t mp_type_bool = {
@ -83,5 +93,7 @@ const mp_obj_type_t mp_type_bool = {
.binary_op = bool_binary_op, .binary_op = bool_binary_op,
}; };
#if !MICROPY_OBJ_IMMEDIATE_OBJS
const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false}; const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false};
const mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true}; const mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true};
#endif

View File

@ -28,9 +28,11 @@
#include "py/obj.h" #include "py/obj.h"
#if !MICROPY_OBJ_IMMEDIATE_OBJS
typedef struct _mp_obj_none_t { typedef struct _mp_obj_none_t {
mp_obj_base_t base; mp_obj_base_t base;
} mp_obj_none_t; } mp_obj_none_t;
#endif
STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)self_in; (void)self_in;
@ -48,4 +50,6 @@ const mp_obj_type_t mp_type_NoneType = {
.unary_op = mp_generic_unary_op, .unary_op = mp_generic_unary_op,
}; };
#if !MICROPY_OBJ_IMMEDIATE_OBJS
const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}}; const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}};
#endif