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:
parent
6f0c83f6e1
commit
d96cfd13e3
@ -113,6 +113,13 @@
|
||||
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
|
||||
#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 */
|
||||
|
||||
|
5
py/obj.c
5
py/obj.c
@ -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)) {
|
||||
return &mp_type_float;
|
||||
#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 {
|
||||
const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
return o->type;
|
||||
|
29
py/obj.h
29
py/obj.h
@ -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.
|
||||
|
||||
#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)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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_TRUE MP_ROM_PTR(&mp_const_true_obj)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MP_ROM_INT
|
||||
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_ZeroDivisionError;
|
||||
|
||||
// Constant objects, globally accessible
|
||||
// The macros are for convenience only
|
||||
// Constant objects, globally accessible: None, False, True
|
||||
// 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_false (MP_OBJ_FROM_PTR(&mp_const_false_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_bool_t mp_const_false_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_tuple_t mp_const_empty_tuple_obj;
|
||||
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
|
||||
|
26
py/objbool.c
26
py/objbool.c
@ -28,21 +28,31 @@
|
||||
|
||||
#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 {
|
||||
mp_obj_base_t base;
|
||||
bool value;
|
||||
} mp_obj_bool_t;
|
||||
|
||||
#endif
|
||||
|
||||
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 (self->value) {
|
||||
if (value) {
|
||||
mp_print_str(print, "true");
|
||||
} else {
|
||||
mp_print_str(print, "false");
|
||||
}
|
||||
} else {
|
||||
if (self->value) {
|
||||
if (value) {
|
||||
mp_print_str(print, "True");
|
||||
} else {
|
||||
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) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in);
|
||||
return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value));
|
||||
bool value = BOOL_VALUE(o_in);
|
||||
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) {
|
||||
mp_obj_bool_t *self = MP_OBJ_TO_PTR(lhs_in);
|
||||
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(self->value), rhs_in);
|
||||
bool value = BOOL_VALUE(lhs_in);
|
||||
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(value), rhs_in);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
#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_true_obj = {{&mp_type_bool}, true};
|
||||
#endif
|
||||
|
@ -28,9 +28,11 @@
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#if !MICROPY_OBJ_IMMEDIATE_OBJS
|
||||
typedef struct _mp_obj_none_t {
|
||||
mp_obj_base_t base;
|
||||
} mp_obj_none_t;
|
||||
#endif
|
||||
|
||||
STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)self_in;
|
||||
@ -48,4 +50,6 @@ const mp_obj_type_t mp_type_NoneType = {
|
||||
.unary_op = mp_generic_unary_op,
|
||||
};
|
||||
|
||||
#if !MICROPY_OBJ_IMMEDIATE_OBJS
|
||||
const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}};
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user