py/obj: Add accessors for type slots and use everywhere.

This is a no-op, but sets the stage for changing the mp_obj_type_t
representation.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
Jim Mussared
2021-07-14 17:14:16 +10:00
committed by Damien George
parent e8355eb163
commit a52cd5b07d
27 changed files with 207 additions and 188 deletions

View File

@@ -59,13 +59,13 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
// Native types don't have parents (at least not from our perspective) so end.
*last_native_base = type;
return count + 1;
} else if (type->parent == NULL) {
} else if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
// No parents so end search here.
return count;
#if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t *)type->parent)->type == &mp_type_tuple) {
} else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
// Multiple parents, search through them all recursively.
const mp_obj_tuple_t *parent_tuple = type->parent;
const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
const mp_obj_t *item = parent_tuple->items;
const mp_obj_t *top = item + parent_tuple->len;
for (; item < top; ++item) {
@@ -77,7 +77,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
#endif
} else {
// A single parent, use iteration to continue the search.
type = type->parent;
type = MP_OBJ_TYPE_GET_SLOT(type, parent);
}
}
}
@@ -118,7 +118,7 @@ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_
// will keep lookup->dest[0]'s value (should be MP_OBJ_NULL on invocation) if attribute
// is not found
// will set lookup->dest[0] to MP_OBJ_SENTINEL if special method was found in a native
// type base via slot id (as specified by lookup->meth_offset). As there can be only one
// type base via slot id (as specified by lookup->slot_offset). As there can be only one
// native base, it's known that it applies to instance->subobj[0]. In most cases, we also
// don't need to know which type it was - because instance->subobj[0] is of that type.
// The only exception is when object is not yet constructed, then we need to know base
@@ -127,7 +127,7 @@ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_
struct class_lookup_data {
mp_obj_instance_t *obj;
qstr attr;
size_t meth_offset;
size_t slot_offset;
mp_obj_t *dest;
bool is_type;
};
@@ -141,19 +141,19 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t
// This avoids extra method_name => slot lookup. On the other hand,
// this should not be applied to class types, as will result in extra
// lookup either.
if (lookup->meth_offset != 0 && mp_obj_is_native_type(type)) {
if (*(void **)((char *)type + lookup->meth_offset) != NULL) {
if (lookup->slot_offset != 0 && mp_obj_is_native_type(type)) {
if (MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(type, lookup->slot_offset)) {
DEBUG_printf("mp_obj_class_lookup: Matched special meth slot (off=%d) for %s\n",
lookup->meth_offset, qstr_str(lookup->attr));
lookup->slot_offset, qstr_str(lookup->attr));
lookup->dest[0] = MP_OBJ_SENTINEL;
return;
}
}
if (type->locals_dict != NULL) {
if (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) {
// search locals_dict (the set of methods/attributes)
assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(type->locals_dict))); // MicroPython restriction, for now
mp_map_t *locals_map = &type->locals_dict->map;
assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(type, locals_dict)))); // MicroPython restriction, for now
mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->map;
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
if (elem != NULL) {
if (lookup->is_type) {
@@ -197,12 +197,12 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t
// attribute not found, keep searching base classes
if (type->parent == NULL) {
if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
DEBUG_printf("mp_obj_class_lookup: No more parents\n");
return;
#if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t *)type->parent)->type == &mp_type_tuple) {
const mp_obj_tuple_t *parent_tuple = type->parent;
} else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
const mp_obj_t *item = parent_tuple->items;
const mp_obj_t *top = item + parent_tuple->len - 1;
for (; item < top; ++item) {
@@ -223,7 +223,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t
type = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
#endif
} else {
type = type->parent;
type = MP_OBJ_TYPE_GET_SLOT(type, parent);
}
if (type == &mp_type_object) {
// Not a "real" type
@@ -239,7 +239,7 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
struct class_lookup_data lookup = {
.obj = self,
.attr = meth,
.meth_offset = offsetof(mp_obj_type_t, print),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(print),
.dest = member,
.is_type = false,
};
@@ -247,7 +247,7 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {
// If there's no __str__, fall back to __repr__
lookup.attr = MP_QSTR___repr__;
lookup.meth_offset = 0;
lookup.slot_offset = 0;
mp_obj_class_lookup(&lookup, self->base.type);
}
@@ -282,7 +282,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
struct class_lookup_data lookup = {
.obj = NULL,
.attr = MP_QSTR___new__,
.meth_offset = offsetof(mp_obj_type_t, make_new),
.slot_offset = offsetof(mp_obj_type_t, make_new),
.dest = init_fn,
.is_type = false,
};
@@ -332,7 +332,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
init_fn[0] = init_fn[1] = MP_OBJ_NULL;
lookup.obj = o;
lookup.attr = MP_QSTR___init__;
lookup.meth_offset = 0;
lookup.slot_offset = 0;
mp_obj_class_lookup(&lookup, self);
if (init_fn[0] != MP_OBJ_NULL) {
mp_obj_t init_ret;
@@ -414,7 +414,7 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
struct class_lookup_data lookup = {
.obj = self,
.attr = op_name,
.meth_offset = offsetof(mp_obj_type_t, unary_op),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(unary_op),
.dest = member,
.is_type = false,
};
@@ -542,7 +542,7 @@ retry:;
struct class_lookup_data lookup = {
.obj = lhs,
.attr = op_name,
.meth_offset = offsetof(mp_obj_type_t, binary_op),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(binary_op),
.dest = dest,
.is_type = false,
};
@@ -608,7 +608,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
struct class_lookup_data lookup = {
.obj = self,
.attr = attr,
.meth_offset = 0,
.slot_offset = 0,
.dest = dest,
.is_type = false,
};
@@ -693,7 +693,7 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val
struct class_lookup_data lookup = {
.obj = self,
.attr = attr,
.meth_offset = 0,
.slot_offset = 0,
.dest = member,
.is_type = false,
};
@@ -815,7 +815,7 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
mp_obj_t member[4] = {MP_OBJ_NULL, MP_OBJ_NULL, index, value};
struct class_lookup_data lookup = {
.obj = self,
.meth_offset = offsetof(mp_obj_type_t, subscr),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(subscr),
.dest = member,
.is_type = false,
};
@@ -850,7 +850,7 @@ STATIC mp_obj_t mp_obj_instance_get_call(mp_obj_t self_in, mp_obj_t *member) {
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR___call__,
.meth_offset = offsetof(mp_obj_type_t, call),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(call),
.dest = member,
.is_type = false,
};
@@ -889,7 +889,7 @@ mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf)
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR___iter__,
.meth_offset = offsetof(mp_obj_type_t, getiter),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(getiter),
.dest = member,
.is_type = false,
};
@@ -901,7 +901,7 @@ mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf)
if (iter_buf == NULL) {
iter_buf = m_new_obj(mp_obj_iter_buf_t);
}
return type->getiter(self->subobj[0], iter_buf);
return MP_OBJ_TYPE_GET_SLOT(type, getiter)(self->subobj[0], iter_buf);
} else {
return mp_call_method_n_kw(0, 0, member);
}
@@ -913,14 +913,14 @@ STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR_, // don't actually look for a method
.meth_offset = offsetof(mp_obj_type_t, buffer),
.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(buffer),
.dest = member,
.is_type = false,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_SENTINEL) {
const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
return type->buffer(self->subobj[0], bufinfo, flags);
return MP_OBJ_TYPE_GET_SLOT(type, buffer)(self->subobj[0], bufinfo, flags);
} else {
return 1; // object does not support buffer protocol
}
@@ -1021,7 +1021,7 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (attr == MP_QSTR___dict__) {
// Returns a read-only dict of the class attributes.
// If the internal locals is not fixed, a copy will be created.
const mp_obj_dict_t *dict = self->locals_dict;
const mp_obj_dict_t *dict = MP_OBJ_TYPE_GET_SLOT_OR_NULL(self, locals_dict);
if (!dict) {
dict = &mp_const_empty_dict_obj;
}
@@ -1040,7 +1040,7 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[0] = mp_const_empty_tuple;
return;
}
mp_obj_t parent_obj = self->parent ? MP_OBJ_FROM_PTR(self->parent) : MP_OBJ_FROM_PTR(&mp_type_object);
mp_obj_t parent_obj = MP_OBJ_TYPE_HAS_SLOT(self, parent) ? MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, parent)) : MP_OBJ_FROM_PTR(&mp_type_object);
#if MICROPY_MULTIPLE_INHERITANCE
if (mp_obj_is_type(parent_obj, &mp_type_tuple)) {
dest[0] = parent_obj;
@@ -1054,7 +1054,7 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
struct class_lookup_data lookup = {
.obj = (mp_obj_instance_t *)self,
.attr = attr,
.meth_offset = 0,
.slot_offset = 0,
.dest = dest,
.is_type = true,
};
@@ -1062,9 +1062,9 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
} else {
// delete/store attribute
if (self->locals_dict != NULL) {
assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(self->locals_dict))); // MicroPython restriction, for now
mp_map_t *locals_map = &self->locals_dict->map;
if (MP_OBJ_TYPE_HAS_SLOT(self, locals_dict)) {
assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, locals_dict)))); // MicroPython restriction, for now
mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(self, locals_dict)->map;
if (locals_map->is_fixed) {
// can't apply delete/store to a fixed map
return;
@@ -1155,43 +1155,44 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
o->base.type = &mp_type_type;
o->flags = base_flags;
o->name = name;
o->print = instance_print;
o->make_new = mp_obj_instance_make_new;
o->call = mp_obj_instance_call;
o->unary_op = instance_unary_op;
o->binary_op = instance_binary_op;
o->attr = mp_obj_instance_attr;
o->subscr = instance_subscr;
o->getiter = mp_obj_instance_getiter;
// o->iternext = ; not implemented
o->buffer = instance_get_buffer;
MP_OBJ_TYPE_SET_SLOT(o, print, instance_print, 0);
MP_OBJ_TYPE_SET_SLOT(o, call, mp_obj_instance_call, 1);
MP_OBJ_TYPE_SET_SLOT(o, unary_op, instance_unary_op, 2);
MP_OBJ_TYPE_SET_SLOT(o, binary_op, instance_binary_op, 3);
MP_OBJ_TYPE_SET_SLOT(o, attr, mp_obj_instance_attr, 4);
MP_OBJ_TYPE_SET_SLOT(o, subscr, instance_subscr, 5);
MP_OBJ_TYPE_SET_SLOT(o, getiter, mp_obj_instance_getiter, 6);
// MP_OBJ_TYPE_SET_SLOT(o, iternext, not implemented)
MP_OBJ_TYPE_SET_SLOT(o, buffer, instance_get_buffer, 7);
if (bases_len > 0) {
// Inherit protocol from a base class. This allows to define an
// abstract base class which would translate C-level protocol to
// Python method calls, and any subclass inheriting from it will
// support this feature.
o->protocol = ((mp_obj_type_t *)MP_OBJ_TO_PTR(bases_items[0]))->protocol;
MP_OBJ_TYPE_SET_SLOT(o, protocol, MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_type_t *)MP_OBJ_TO_PTR(bases_items[0])), protocol), 8);
if (bases_len >= 2) {
#if MICROPY_MULTIPLE_INHERITANCE
o->parent = MP_OBJ_TO_PTR(bases_tuple);
MP_OBJ_TYPE_SET_SLOT(o, parent, MP_OBJ_TO_PTR(bases_tuple), 9);
#else
mp_raise_NotImplementedError(MP_ERROR_TEXT("multiple inheritance not supported"));
#endif
} else {
o->parent = MP_OBJ_TO_PTR(bases_items[0]);
MP_OBJ_TYPE_SET_SLOT(o, parent, MP_OBJ_TO_PTR(bases_items[0]), 9);
}
}
o->locals_dict = MP_OBJ_TO_PTR(locals_dict);
mp_obj_dict_t *locals_ptr = MP_OBJ_TO_PTR(locals_dict);
MP_OBJ_TYPE_SET_SLOT(o, locals_dict, locals_ptr, 10);
#if ENABLE_SPECIAL_ACCESSORS
// Check if the class has any special accessor methods
if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
for (size_t i = 0; i < o->locals_dict->map.alloc; i++) {
if (mp_map_slot_is_filled(&o->locals_dict->map, i)) {
const mp_map_elem_t *elem = &o->locals_dict->map.table[i];
for (size_t i = 0; i < locals_ptr->map.alloc; i++) {
if (mp_map_slot_is_filled(&locals_ptr->map, i)) {
const mp_map_elem_t *elem = &locals_ptr->map.table[i];
if (check_for_special_accessors(elem->key, elem->value)) {
o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
break;
@@ -1207,7 +1208,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
mp_raise_TypeError(MP_ERROR_TEXT("multiple bases have instance lay-out conflict"));
}
mp_map_t *locals_map = &o->locals_dict->map;
mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(o, locals_dict)->map;
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
if (elem != NULL) {
// __new__ slot exists; check if it is a function
@@ -1268,21 +1269,21 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
struct class_lookup_data lookup = {
.obj = MP_OBJ_TO_PTR(self->obj),
.attr = attr,
.meth_offset = 0,
.slot_offset = 0,
.dest = dest,
.is_type = false,
};
// Allow a call super().__init__() to reach any native base classes
// Allow a call super().__init__() to reach any native base classes.
if (attr == MP_QSTR___init__) {
lookup.meth_offset = offsetof(mp_obj_type_t, make_new);
lookup.slot_offset = offsetof(mp_obj_type_t, make_new);
}
if (type->parent == NULL) {
if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
// no parents, do nothing
#if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t *)type->parent)->type == &mp_type_tuple) {
const mp_obj_tuple_t *parent_tuple = type->parent;
} else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
size_t len = parent_tuple->len;
const mp_obj_t *items = parent_tuple->items;
for (size_t i = 0; i < len; i++) {
@@ -1292,14 +1293,15 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
// and we don't want to lookup native methods in object.
continue;
}
mp_obj_class_lookup(&lookup, (mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]));
if (dest[0] != MP_OBJ_NULL) {
break;
}
}
#endif
} else if (type->parent != &mp_type_object) {
mp_obj_class_lookup(&lookup, type->parent);
} else if (MP_OBJ_TYPE_GET_SLOT(type, parent) != &mp_type_object) {
mp_obj_class_lookup(&lookup, MP_OBJ_TYPE_GET_SLOT(type, parent));
}
if (dest[0] != MP_OBJ_NULL) {
@@ -1311,9 +1313,9 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return;
}
// Reset meth_offset so we don't look up any native methods in object,
// Reset slot_offset so we don't look up any native methods in object,
// because object never takes up the native base-class slot.
lookup.meth_offset = 0;
lookup.slot_offset = 0;
mp_obj_class_lookup(&lookup, &mp_type_object);
}
@@ -1352,13 +1354,13 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
const mp_obj_type_t *self = MP_OBJ_TO_PTR(object);
if (self->parent == NULL) {
if (!MP_OBJ_TYPE_HAS_SLOT(self, parent)) {
// type has no parents
return false;
#if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t *)self->parent)->type == &mp_type_tuple) {
} else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(self, parent))->type == &mp_type_tuple) {
// get the base objects (they should be type objects)
const mp_obj_tuple_t *parent_tuple = self->parent;
const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(self, parent);
const mp_obj_t *item = parent_tuple->items;
const mp_obj_t *top = item + parent_tuple->len - 1;
@@ -1374,7 +1376,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
#endif
} else {
// type has 1 parent
object = MP_OBJ_FROM_PTR(self->parent);
object = MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, parent));
}
}
}