summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--extmod/moductypes.c21
-rw-r--r--py/obj.h17
-rw-r--r--py/objboundmeth.c8
-rw-r--r--py/objcomplex.c8
-rw-r--r--py/objexcept.c10
-rw-r--r--py/objfun.c8
-rw-r--r--py/objmodule.c64
-rw-r--r--py/objnamedtuple.c29
-rw-r--r--py/objrange.c8
-rw-r--r--py/objtype.c106
-rw-r--r--py/objtype.h5
-rw-r--r--py/runtime.c11
-rw-r--r--py/vm.c4
13 files changed, 172 insertions, 127 deletions
diff --git a/extmod/moductypes.c b/extmod/moductypes.c
index 7e7128a269..f9f0ca79bc 100644
--- a/extmod/moductypes.c
+++ b/extmod/moductypes.c
@@ -482,13 +482,17 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
return MP_OBJ_NULL;
}
-STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
- mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
- *dest = val;
-}
-
-STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) {
- return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL;
+STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] == MP_OBJ_NULL) {
+ // load attribute
+ mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
+ dest[0] = val;
+ } else {
+ // delete/store attribute
+ if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) {
+ dest[0] = MP_OBJ_NULL; // indicate success
+ }
+ }
}
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 = {
.name = MP_QSTR_struct,
.print = uctypes_struct_print,
.make_new = uctypes_struct_make_new,
- .load_attr = uctypes_struct_load_attr,
- .store_attr = uctypes_struct_store_attr,
+ .attr = uctypes_struct_attr,
.subscr = uctypes_struct_subscr,
};
diff --git a/py/obj.h b/py/obj.h
index 448db762af..a5423f0824 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -265,8 +265,7 @@ typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, mp_uint_t n_args, mp_uin
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);
typedef mp_obj_t (*mp_unary_op_fun_t)(mp_uint_t op, mp_obj_t);
typedef mp_obj_t (*mp_binary_op_fun_t)(mp_uint_t op, mp_obj_t, mp_obj_t);
-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
-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
+typedef void (*mp_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
typedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
typedef struct _mp_method_t {
@@ -330,8 +329,18 @@ struct _mp_obj_type_t {
mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported
- mp_load_attr_fun_t load_attr;
- mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute
+ // implements load, store and delete attribute
+ //
+ // dest[0] = MP_OBJ_NULL means load
+ // return: for fail, do nothing
+ // for attr, dest[0] = value
+ // for method, dest[0] = method, dest[1] = self
+ //
+ // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete
+ // dest[0,1] = {MP_OBJ_SENTINEL, object} means store
+ // return: for fail, do nothing
+ // for success set dest[0] = MP_OBJ_NULL
+ mp_attr_fun_t attr;
mp_subscr_fun_t subscr; // implements load, store, delete subscripting
// value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store
diff --git a/py/objboundmeth.c b/py/objboundmeth.c
index 84d201277f..0f9ff08c81 100644
--- a/py/objboundmeth.c
+++ b/py/objboundmeth.c
@@ -71,7 +71,11 @@ STATIC mp_obj_t bound_meth_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_
}
#if MICROPY_PY_FUNCTION_ATTRS
-STATIC void bound_meth_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] != MP_OBJ_NULL) {
+ // not load attribute
+ return;
+ }
if (attr == MP_QSTR___name__) {
mp_obj_bound_meth_t *o = self_in;
dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth));
@@ -87,7 +91,7 @@ STATIC const mp_obj_type_t mp_type_bound_meth = {
#endif
.call = bound_meth_call,
#if MICROPY_PY_FUNCTION_ATTRS
- .load_attr = bound_meth_load_attr,
+ .attr = bound_meth_attr,
#endif
};
diff --git a/py/objcomplex.c b/py/objcomplex.c
index 1415068438..f4a68851a5 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -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
return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
}
-STATIC void complex_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] != MP_OBJ_NULL) {
+ // not load attribute
+ return;
+ }
mp_obj_complex_t *self = self_in;
if (attr == MP_QSTR_real) {
dest[0] = mp_obj_new_float(self->real);
@@ -157,7 +161,7 @@ const mp_obj_type_t mp_type_complex = {
.make_new = complex_make_new,
.unary_op = complex_unary_op,
.binary_op = complex_binary_op,
- .load_attr = complex_load_attr,
+ .attr = complex_attr,
};
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {
diff --git a/py/objexcept.c b/py/objexcept.c
index 987a54fda7..2d23f160a2 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -140,7 +140,11 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
}
}
-STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] != MP_OBJ_NULL) {
+ // not load attribute
+ return;
+ }
mp_obj_exception_t *self = self_in;
if (attr == MP_QSTR_args) {
dest[0] = self->args;
@@ -168,7 +172,7 @@ const mp_obj_type_t mp_type_BaseException = {
.name = MP_QSTR_BaseException,
.print = mp_obj_exception_print,
.make_new = mp_obj_exception_make_new,
- .load_attr = exception_load_attr,
+ .attr = exception_attr,
.locals_dict = (mp_obj_t)&exc_locals_dict,
};
@@ -181,7 +185,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
.name = MP_QSTR_ ## exc_name, \
.print = mp_obj_exception_print, \
.make_new = mp_obj_exception_make_new, \
- .load_attr = exception_load_attr, \
+ .attr = exception_attr, \
.bases_tuple = (mp_obj_t)&mp_type_ ## base_name ## _base_tuple, \
};
diff --git a/py/objfun.c b/py/objfun.c
index 76adfef500..f00a90a089 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -296,7 +296,11 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
}
#if MICROPY_PY_FUNCTION_ATTRS
-STATIC void fun_bc_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] != MP_OBJ_NULL) {
+ // not load attribute
+ return;
+ }
if (attr == MP_QSTR___name__) {
dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in));
}
@@ -311,7 +315,7 @@ const mp_obj_type_t mp_type_fun_bc = {
#endif
.call = fun_bc_call,
#if MICROPY_PY_FUNCTION_ATTRS
- .load_attr = fun_bc_load_attr,
+ .attr = fun_bc_attr,
#endif
};
diff --git a/py/objmodule.c b/py/objmodule.c
index 02292ff785..971c7f38c5 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -51,48 +51,48 @@ STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *e
print(env, "<module '%s'>", name);
}
-STATIC void module_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_module_t *self = self_in;
- mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
- if (elem != NULL) {
- dest[0] = elem->value;
- }
-}
-
-STATIC bool module_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
- mp_obj_module_t *self = self_in;
- mp_obj_dict_t *dict = self->globals;
- if (dict->map.is_fixed) {
- #if MICROPY_CAN_OVERRIDE_BUILTINS
- if (dict == &mp_module_builtins_globals) {
- if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
- MP_STATE_VM(mp_module_builtins_override_dict) = mp_obj_new_dict(1);
- }
- dict = MP_STATE_VM(mp_module_builtins_override_dict);
- } else
- #endif
- {
- // can't delete or store to fixed map
- return false;
+ if (dest[0] == MP_OBJ_NULL) {
+ // load attribute
+ mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
+ if (elem != NULL) {
+ dest[0] = elem->value;
}
- }
- if (value == MP_OBJ_NULL) {
- // delete attribute
- mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr));
} else {
- // store attribute
- // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
- mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), value);
+ // delete/store attribute
+ mp_obj_dict_t *dict = self->globals;
+ if (dict->map.is_fixed) {
+ #if MICROPY_CAN_OVERRIDE_BUILTINS
+ if (dict == &mp_module_builtins_globals) {
+ if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
+ MP_STATE_VM(mp_module_builtins_override_dict) = mp_obj_new_dict(1);
+ }
+ dict = MP_STATE_VM(mp_module_builtins_override_dict);
+ } else
+ #endif
+ {
+ // can't delete or store to fixed map
+ return;
+ }
+ }
+ if (dest[1] == MP_OBJ_NULL) {
+ // delete attribute
+ mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr));
+ } else {
+ // store attribute
+ // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
+ mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), dest[1]);
+ }
+ dest[0] = MP_OBJ_NULL; // indicate success
}
- return true;
}
const mp_obj_type_t mp_type_module = {
{ &mp_type_type },
.name = MP_QSTR_module,
.print = module_print,
- .load_attr = module_load_attr,
- .store_attr = module_store_attr,
+ .attr = module_attr,
};
mp_obj_t mp_obj_new_module(qstr module_name) {
diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c
index 1996b41219..9cc6da1b7a 100644
--- a/py/objnamedtuple.c
+++ b/py/objnamedtuple.c
@@ -68,20 +68,20 @@ STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), voi
print(env, ")");
}
-STATIC void namedtuple_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
- mp_obj_namedtuple_t *self = self_in;
- int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr);
- if (id == -1) {
- return;
+STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] == MP_OBJ_NULL) {
+ // load attribute
+ mp_obj_namedtuple_t *self = self_in;
+ int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr);
+ if (id == -1) {
+ return;
+ }
+ dest[0] = self->tuple.items[id];
+ } else {
+ // delete/store attribute
+ // provide more detailed error message than we'd get by just returning
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute"));
}
- dest[0] = self->tuple.items[id];
-}
-
-STATIC bool namedtuple_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
- (void)self_in;
- (void)attr;
- (void)value;
- nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute"));
}
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
o->base.make_new = namedtuple_make_new;
o->base.unary_op = mp_obj_tuple_unary_op;
o->base.binary_op = mp_obj_tuple_binary_op;
- o->base.load_attr = namedtuple_load_attr;
- o->base.store_attr = namedtuple_store_attr;
+ o->base.attr = namedtuple_attr;
o->base.subscr = mp_obj_tuple_subscr;
o->base.getiter = mp_obj_tuple_getiter;
o->base.bases_tuple = (mp_obj_t)&namedtuple_base_tuple;
diff --git a/py/objrange.c b/py/objrange.c
index ff62cc5b81..9f7e6591e1 100644
--- a/py/objrange.c
+++ b/py/objrange.c
@@ -168,7 +168,11 @@ STATIC mp_obj_t range_getiter(mp_obj_t o_in) {
#if MICROPY_PY_BUILTINS_RANGE_ATTRS
-STATIC void range_load_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
+STATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] != MP_OBJ_NULL) {
+ // not load attribute
+ return;
+ }
mp_obj_range_t *o = o_in;
if (attr == MP_QSTR_start) {
dest[0] = mp_obj_new_int(o->start);
@@ -189,6 +193,6 @@ const mp_obj_type_t mp_type_range = {
.subscr = range_subscr,
.getiter = range_getiter,
#if MICROPY_PY_BUILTINS_RANGE_ATTRS
- .load_attr = range_load_attr,
+ .attr = range_attr,
#endif
};
diff --git a/py/objtype.c b/py/objtype.c
index a5fb17f2ce..cb7110572d 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -440,7 +440,7 @@ STATIC mp_obj_t instance_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
}
}
-void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
// logic: look in instance members then class locals
assert(is_instance_type(mp_obj_get_type(self_in)));
mp_obj_instance_t *self = self_in;
@@ -512,7 +512,7 @@ void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
}
-bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
+STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
mp_obj_instance_t *self = self_in;
#if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS
@@ -602,6 +602,16 @@ bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
}
}
+void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] == MP_OBJ_NULL) {
+ mp_obj_instance_load_attr(self_in, attr, dest);
+ } else {
+ if (mp_obj_instance_store_attr(self_in, attr, dest[1])) {
+ dest[0] = MP_OBJ_NULL; // indicate success
+ }
+ }
+}
+
STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_instance_t *self = self_in;
mp_obj_t member[2] = {MP_OBJ_NULL};
@@ -774,52 +784,52 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, co
return o;
}
-// for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self
-STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
mp_obj_type_t *self = self_in;
-#if MICROPY_CPYTHON_COMPAT
- if (attr == MP_QSTR___name__) {
- dest[0] = MP_OBJ_NEW_QSTR(self->name);
- return;
- }
-#endif
- struct class_lookup_data lookup = {
- .obj = self_in,
- .attr = attr,
- .meth_offset = 0,
- .dest = dest,
- .is_type = true,
- };
- mp_obj_class_lookup(&lookup, self);
-}
-STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
- assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
- mp_obj_type_t *self = self_in;
+ if (dest[0] == MP_OBJ_NULL) {
+ // load attribute
+ #if MICROPY_CPYTHON_COMPAT
+ if (attr == MP_QSTR___name__) {
+ dest[0] = MP_OBJ_NEW_QSTR(self->name);
+ return;
+ }
+ #endif
+ struct class_lookup_data lookup = {
+ .obj = self_in,
+ .attr = attr,
+ .meth_offset = 0,
+ .dest = dest,
+ .is_type = true,
+ };
+ mp_obj_class_lookup(&lookup, self);
+ } else {
+ // delete/store attribute
- // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
+ // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
- if (self->locals_dict != NULL) {
- assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
- mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict);
- if (value == MP_OBJ_NULL) {
- // delete attribute
- mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
- // note that locals_map may be in ROM, so remove will fail in that case
- return elem != NULL;
- } else {
- // store attribute
- mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
- // note that locals_map may be in ROM, so add will fail in that case
- if (elem != NULL) {
- elem->value = value;
- return true;
+ if (self->locals_dict != NULL) {
+ assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
+ mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict);
+ if (dest[1] == MP_OBJ_NULL) {
+ // delete attribute
+ mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
+ // note that locals_map may be in ROM, so remove will fail in that case
+ if (elem != NULL) {
+ dest[0] = MP_OBJ_NULL; // indicate success
+ }
+ } else {
+ // store attribute
+ mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ // note that locals_map may be in ROM, so add will fail in that case
+ if (elem != NULL) {
+ elem->value = dest[1];
+ dest[0] = MP_OBJ_NULL; // indicate success
+ }
}
}
}
-
- return false;
}
const mp_obj_type_t mp_type_type = {
@@ -828,8 +838,7 @@ const mp_obj_type_t mp_type_type = {
.print = type_print,
.make_new = type_make_new,
.call = type_call,
- .load_attr = type_load_attr,
- .store_attr = type_store_attr,
+ .attr = type_attr,
};
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
@@ -865,8 +874,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
o->call = mp_obj_instance_call;
o->unary_op = instance_unary_op;
o->binary_op = instance_binary_op;
- o->load_attr = mp_obj_instance_load_attr;
- o->store_attr = mp_obj_instance_store_attr;
+ o->attr = mp_obj_instance_attr;
o->subscr = instance_subscr;
o->getiter = instance_getiter;
//o->iternext = ; not implemented
@@ -921,8 +929,12 @@ STATIC mp_obj_t super_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
return mp_obj_new_super(args[0], args[1]);
}
-// for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self
-STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ if (dest[0] != MP_OBJ_NULL) {
+ // not load attribute
+ return;
+ }
+
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super));
mp_obj_super_t *self = self_in;
@@ -960,7 +972,7 @@ const mp_obj_type_t mp_type_super = {
.name = MP_QSTR_super,
.print = super_print,
.make_new = super_make_new,
- .load_attr = super_load_attr,
+ .attr = super_attr,
};
mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj) {
diff --git a/py/objtype.h b/py/objtype.h
index 176e802d24..de1909b1e1 100644
--- a/py/objtype.h
+++ b/py/objtype.h
@@ -37,9 +37,8 @@ typedef struct _mp_obj_instance_t {
// TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them
} mp_obj_instance_t;
-// these need to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work
-void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
-bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value);
+// this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work
+void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
// these need to be exposed so mp_obj_is_callable can work correctly
bool mp_obj_instance_is_callable(mp_obj_t self_in);
diff --git a/py/runtime.c b/py/runtime.c
index 2bb9a02641..b04a4af139 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -917,9 +917,9 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
dest[0] = (mp_obj_t)&mp_builtin_next_obj;
dest[1] = obj;
- } else if (type->load_attr != NULL) {
+ } else if (type->attr != NULL) {
// this type can do its own load, so call it
- type->load_attr(obj, attr, dest);
+ type->attr(obj, attr, dest);
} else if (type->locals_dict != NULL) {
// generic method lookup
@@ -961,8 +961,11 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
mp_obj_type_t *type = mp_obj_get_type(base);
- if (type->store_attr != NULL) {
- if (type->store_attr(base, attr, value)) {
+ if (type->attr != NULL) {
+ mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value};
+ type->attr(base, attr, dest);
+ if (dest[0] == MP_OBJ_NULL) {
+ // success
return;
}
}
diff --git a/py/vm.c b/py/vm.c
index d81f5580e2..55203b0748 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -315,7 +315,7 @@ dispatch_loop:
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_obj_t top = TOP();
- if (mp_obj_get_type(top)->load_attr == mp_obj_instance_load_attr) {
+ if (mp_obj_get_type(top)->attr == mp_obj_instance_attr) {
mp_obj_instance_t *self = top;
mp_uint_t x = *ip;
mp_obj_t key = MP_OBJ_NEW_QSTR(qst);
@@ -405,7 +405,7 @@ dispatch_loop:
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_obj_t top = TOP();
- if (mp_obj_get_type(top)->store_attr == mp_obj_instance_store_attr && sp[-1] != MP_OBJ_NULL) {
+ if (mp_obj_get_type(top)->attr == mp_obj_instance_attr && sp[-1] != MP_OBJ_NULL) {
mp_obj_instance_t *self = top;
mp_uint_t x = *ip;
mp_obj_t key = MP_OBJ_NEW_QSTR(qst);