8000 py: Combine load_attr and store_attr type methods. · micropython/micropython@6a27edc · GitHub
[go: up one dir, main page]

Skip to content

Commit 6a27edc

Browse files
committed
py: Combine load_attr and store_attr type methods.
This simplifies the API for objects and reduces code size (by around 400 bytes on Thumb2, and around 2k on x86). It reduced performance a little, measured as 1% decrease in Pystone score.
1 parent 2686f9b commit 6a27edc

13 files changed

+176
-131
lines changed

extmod/moductypes.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -482,13 +482,17 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
482482
return MP_OBJ_NULL;
483483
}
484484

485-
STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
486-
mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
487-
*dest = val;
488-
}
489-
490-
STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) {
491-
return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL;
485+
STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
486+
if (dest[0] == MP_OBJ_NULL) {
487+
// load attribute
488+
mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
489+
dest[0] = val;
490+
} else {
491+
// delete/store attribute
492+
if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) {
493+
dest[0] = MP_OBJ_NULL; // indicate success
494+
}
495+
}
492496
}
493497

494498
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
@@ -589,8 +593,7 @@ STATIC const mp_obj_type_t uctypes_struct_type = {
589593
.name = MP_QSTR_struct,
590594
.print = uctypes_struct_print,
591595
.make_new = uctypes_struct_make_new,
592-
.load_attr = uctypes_struct_load_attr,
593-
.store_attr = uctypes_struct_store_attr,
596+
.attr = uctypes_struct_attr,
594597
.subscr = uctypes_struct_subscr,
595598
};
596599

py/obj.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,7 @@ typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, mp_uint_t n_args, mp_uin
232232
typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
233233
typedef mp_obj_t (*mp_unary_op_fun_t)(mp_uint_t op, mp_obj_t);
234234
typedef mp_obj_t (*mp_binary_op_fun_t)(mp_uint_t op, mp_obj_t, mp_obj_t);
235-
typedef void (*mp_load_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); // for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self
236-
typedef bool (*mp_store_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t value); // return true if store succeeded; if value==MP_OBJ_NULL then delete
235+
typedef void (*mp_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
237236
typedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
238237

239238
typedef struct _mp_method_t {
@@ -297,8 +296,18 @@ struct _mp_obj_type_t {
297296
mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported
298297
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported
299298

300-
mp_load_attr_fun_t load_attr;
301-
mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute
299+
// implements load, store and delete attribute
300+
//
301+
// dest[0] = MP_OBJ_NULL means load
302+
// return: for fail, do nothing
303+
// for attr, dest[0] = value
304+
// for method, dest[0] = method, dest[1] = self
305+
//
306+
// dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete
307+
// dest[0,1] = {MP_OBJ_SENTINEL, object} means store
308+
// return: for fail, do nothing
309+
// for success set dest[0] = MP_OBJ_NULL
310+
mp_attr_fun_t attr;
302311

303312
mp_subscr_fun_t subscr; // implements load, store, delete subscripting
304313
// value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store

py/objboundmeth.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@ STATIC mp_obj_t bound_meth_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_
7171
}
7272

7373
#if MICROPY_PY_FUNCTION_ATTRS
74-
STATIC void bound_meth_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
75-
if(attr == MP_QSTR___name__) {
74+
STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
75+
if (dest[0] != MP_OBJ_NULL) {
76+
// not load attribute
77+
return;
78+
}
79+
if (attr == MP_QSTR___name__) {
7680
mp_obj_bound_meth_t *o = self_in;
7781
dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth));
7882
}
@@ -87,7 +91,7 @@ const mp_obj_type_t bound_meth_type = {
8791
#endif
8892
.call = bound_meth_call,
8993
#if MICROPY_PY_FUNCTION_ATTRS
90-
.load_attr = bound_meth_load_attr,
94+
.attr = bound_meth_attr,
9195
#endif
9296
};
9397

py/objcomplex.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,11 @@ STATIC mp_obj_t complex_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in
141141
return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
142142
}
143143

144-
STATIC void complex_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
144+
STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
145+
if (dest[0] != MP_OBJ_NULL) {
146+
// not load attribute
147+
return;
148+
}
145149
mp_obj_complex_t *self = self_in;
146150
if (attr == MP_QSTR_real) {
147151
dest[0] = mp_obj_new_float(self->real);
@@ -157,7 +161,7 @@ const mp_obj_type_t mp_type_complex = {
157161
.make_new = complex_make_new,
158162
.unary_op = complex_unary_op,
159163
.binary_op = complex_binary_op,
160-
.load_attr = complex_load_attr,
164+
.attr = complex_attr,
161165
};
162166

163167
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {

py/objexcept.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,11 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
140140
}
141141
}
142142

143-
STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
143+
STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
144+
if (dest[0] != MP_OBJ_NULL) {
145+
// not load attribute
146+
return;
147+
}
144148
mp_obj_exception_t *self = self_in;
145149
if (attr == MP_QSTR_args) {
146150
dest[0] = self->args;
@@ -168,7 +172,7 @@ const mp_obj_type_t mp_type_BaseException = {
168172
.name = MP_QSTR_BaseException,
169173
.print = mp_obj_exception_print,
170174
.make_new = mp_obj_exception_make_new,
171-
.load_attr = exception_load_attr,
175+
.attr = exception_attr,
172176
.locals_dict = (mp_obj_t)&exc_locals_dict,
173177
};
174178

@@ -181,7 +185,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
181185
.name = MP_QSTR_ ## exc_name, \
182186
.print = mp_obj_exception_print, \
183187
.make_new = mp_obj_exception_make_new, \
184-
.load_attr = exception_load_attr, \
188+
.attr = exception_attr, \
185189
.bases_tuple = (mp_obj_t)&mp_type_ ## base_name ## _base_tuple, \
186190
};
187191

py/objfun.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,12 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
247247
}
248248

249249
#if MICROPY_PY_FUNCTION_ATTRS
250-
STATIC void fun_bc_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
251-
if(attr == MP_QSTR___name__) {
250+
STATIC void fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
251+
if (dest[0] != MP_OBJ_NULL) {
252+
// not load attribute
253+
return;
254+
}
255+
if (attr == MP_QSTR___name__) {
252256
dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in));
253257
}
254258
}
@@ -262,7 +266,7 @@ const mp_obj_type_t mp_type_fun_bc = {
262266
#endif
263267
.call = fun_bc_call,
264268
#if MICROPY_PY_FUNCTION_ATTRS
265-
.load_attr = fun_bc_load_attr,
269+
.attr = fun_bc_attr,
266270
#endif
267271
};
268272

py/objmodule.c

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -51,48 +51,48 @@ STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *e
5151
print(env, "<module '%s'>", name);
5252
}
5353

54-
STATIC void module_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
54+
STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
5555
mp_obj_module_t *self = self_in;
56-
mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
57-
if (elem != NULL) {
58-
dest[0] = elem->value;
59-
}
60-
}
61-
62-
STATIC bool module_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
63-
mp_obj_module_t *self = self_in;
64-
mp_obj_dict_t *dict = self->globals;
65-
if (dict->map.is_fixed) {
66-
#if MICROPY_CAN_OVERRIDE_BUILTINS
67-
if (dict == &mp_module_builtins_globals) {
68-
if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
69-
MP_STATE_VM(mp_module_builtins_override_dict) = mp_obj_new_dict(1);
70-
}
71-
dict = MP_STATE_VM(mp_module_builtins_override_dict);
72-
} else
73-
#endif
74-
{
75-
// can't delete or store to fixed map
76-
return false;
56+
if (dest[0] == MP_OBJ_NULL) {
57+
// load attribute
58+
mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
59+
if (elem != NULL) {
60+
dest[0] = elem->value;
7761
}
78-
}
79-
if (value == MP_OBJ_NULL) {
80-
// delete attribute
81-
mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr));
8262
} else {
83-
// store attribute
84-
// TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
85-
mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), value);
63+
// delete/store attribute
64+
mp_obj_dict_t *dict = self->globals;
65+
if (dict->map.is_fixed) {
66+
#if MICROPY_CAN_OVERRIDE_BUILTINS
67+
if (dict == &mp_module_builtins_globals) {
68+
if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
69+
MP_STATE_VM(mp_module_builtins_override_dict) = mp_obj_new_dict(1);
70+
}
71+
dict = MP_STATE_VM(mp_module_builtins_override_dict);
72+
} else
73+
#endif
74+
{
75+
// can't delete or store to fixed map
76+
return;
77+
}
78+
}
79+
if (dest[1] == MP_OBJ_NULL) {
80+
// delete attribute
81+
mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr));
82+
} else {
83+
// store attribute
84+
// TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
85+
mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), dest[1]);
86+
}
87+
dest[0] = MP_OBJ_NULL; // indicate success
8688
}
87-
return true;
8889
}
8990

9091
const mp_obj_type_t mp_type_module = {
9192
{ &mp_type_type },
9293
.name = MP_QSTR_module,
9394
.print = module_print,
94-
.load_attr = module_load_attr,
95-
.store_attr = module_store_attr,
95+
.attr = module_attr,
9696
};
9797

9898
mp_obj_t mp_obj_new_module(qstr module_name) {

py/objnamedtuple.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,20 @@ STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), voi
6868
print(env, ")");
6969
}
7070

71-
STATIC void namedtuple_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
72-
mp_obj_namedtuple_t *self = self_in;
73-
int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr);
74-
if (id == -1) {
75-
return;
71+
STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
72+
if (dest[0] == MP_OBJ_NULL) {
73+
// load attribute
74+
mp_obj_namedtuple_t *self = self_in;
75+
int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr);
76+
if (id == -1) {
77+
return;
78+
}
79+
dest[0] = self->tuple.items[id];
80+
} else {
81+
// delete/store attribute
82+
// provide more detailed error message
83+
nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute"));
7684
}
77-
dest[0] = self->tuple.items[id];
78-
}
79-
80-
STATIC bool namedtuple_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
81-
(void)self_in;
82-
(void)attr;
83-
(void)value;
84-
nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute"));
8585
}
8686

8787
STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
@@ -154,8 +154,7 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj
154154
o->base.make_new = namedtuple_make_new;
155155
o->base.unary_op = mp_obj_tuple_unary_op;
156156
o->base.binary_op = mp_obj_tuple_binary_op;
157-
o->base.load_attr = namedtuple_load_attr;
158-
o->base.store_attr = namedtuple_store_attr;
157+
o->base.attr = namedtuple_attr;
159158
o->base.subscr = mp_obj_tuple_subscr;
160159
o->base.getiter = mp_obj_tuple_getiter;
161160
o->base.bases_tuple = (mp_obj_t)&namedtuple_base_tuple;

py/objrange.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,11 @@ STATIC mp_obj_t range_getiter(mp_obj_t o_in) {
168168

169169

170170
#if MICROPY_PY_BUILTINS_RANGE_ATTRS
171-
STATIC void range_load_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
171+
STATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
172+
if (dest[0] != MP_OBJ_NULL) {
173+
// not load attribute
174+
return;
175+
}
172176
mp_obj_range_t *o = o_in;
173177
if (attr == MP_QSTR_start) {
174178
dest[0] = mp_obj_new_int(o->start);
@@ -189,6 +193,6 @@ const mp_obj_type_t mp_type_range = {
5833
189193
.subscr = range_subscr,
190194
.getiter = range_getiter,
191195
#if MICROPY_PY_BUILTINS_RANGE_ATTRS
192-
.load_attr = range_load_attr,
196+
.attr = range_attr,
193197
#endif
194198
};

0 commit comments

Comments
 (0)
0