objtype: Optimize stack usage mp_obj_class_lookup().

As before, instead of pushing constant values on stack again and again, just
pass around pointer to a structure.
pull/675/head
Paul Sokolovsky 2014-06-08 20:50:12 +03:00
rodzic 57b4dfa9c9
commit 639863d36e
1 zmienionych plików z 116 dodań i 34 usunięć

Wyświetl plik

@ -98,18 +98,25 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
// 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 native type to construct
// instance->subobj[0]. This case is handled via instance_count_native_bases() though.
STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type, qstr attr, machine_uint_t meth_offset, mp_obj_t *dest) {
assert(dest[0] == NULL);
assert(dest[1] == NULL);
struct class_lookup_data {
mp_obj_instance_t *obj;
qstr attr;
machine_uint_t meth_offset;
mp_obj_t *dest;
};
STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {
assert(lookup->dest[0] == NULL);
assert(lookup->dest[1] == NULL);
for (;;) {
// Optimize special method lookup for native types
// 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 (meth_offset != 0 && is_native_type(type)) {
if (*(void**)((char*)type + meth_offset) != NULL) {
DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(attr));
dest[0] = MP_OBJ_SENTINEL;
if (lookup->meth_offset != 0 && is_native_type(type)) {
if (*(void**)((char*)type + lookup->meth_offset) != NULL) {
DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(lookup->attr));
lookup->dest[0] = MP_OBJ_SENTINEL;
return;
}
}
@ -118,13 +125,13 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
// search locals_dict (the set of methods/attributes)
assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
if (elem != NULL) {
dest[0] = elem->value;
if (o != MP_OBJ_NULL && is_native_type(type)) {
instance_convert_return_attr(o->subobj[0], type, elem->value, dest);
lookup->dest[0] = elem->value;
if (lookup->obj != MP_OBJ_NULL && is_native_type(type)) {
instance_convert_return_attr(lookup->obj->subobj[0], type, elem->value, lookup->dest);
} else {
instance_convert_return_attr(o, type, elem->value, dest);
instance_convert_return_attr(lookup->obj, type, elem->value, lookup->dest);
}
return;
}
@ -132,9 +139,9 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
// Try this for completeness, but all native methods should be statically defined
// in locals_dict, and would be handled by above.
if (o != MP_OBJ_NULL && is_native_type(type)) {
mp_load_method_maybe(o->subobj[0], attr, dest);
if (dest[0] != MP_OBJ_NULL) {
if (lookup->obj != MP_OBJ_NULL && is_native_type(type)) {
mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest);
if (lookup->dest[0] != MP_OBJ_NULL) {
return;
}
}
@ -159,8 +166,8 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
// Not a "real" type
continue;
}
mp_obj_class_lookup(o, bt, attr, meth_offset, dest);
if (dest[0] != MP_OBJ_NULL) {
mp_obj_class_lookup(lookup, bt);
if (lookup->dest[0] != MP_OBJ_NULL) {
return;
}
}
@ -179,10 +186,18 @@ STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void
mp_obj_instance_t *self = self_in;
qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, meth, offsetof(mp_obj_type_t, print), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = meth,
.meth_offset = offsetof(mp_obj_type_t, print),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {
// If there's no __str__, fall back to __repr__
mp_obj_class_lookup(self, self->base.type, MP_QSTR___repr__, 0, member);
lookup.attr = MP_QSTR___repr__;
lookup.meth_offset = 0;
mp_obj_class_lookup(&lookup, self->base.type);
}
if (member[0] == MP_OBJ_SENTINEL) {
@ -228,7 +243,13 @@ mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_ob
// look for __new__ function
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(NULL, self, MP_QSTR___new__, offsetof(mp_obj_type_t, make_new), init_fn);
struct class_lookup_data lookup = {
.obj = NULL,
.attr = MP_QSTR___new__,
.meth_offset = offsetof(mp_obj_type_t, make_new),
.dest = init_fn,
};
mp_obj_class_lookup(&lookup, self);
mp_obj_t new_ret = o;
if (init_fn[0] == MP_OBJ_SENTINEL) {
@ -259,7 +280,10 @@ mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_ob
// now call Python class __init__ function with all args
init_fn[0] = init_fn[1] = NULL;
mp_obj_class_lookup(o, self, MP_QSTR___init__, 0, init_fn);
lookup.obj = o;
lookup.attr = MP_QSTR___init__;
lookup.meth_offset = 0;
mp_obj_class_lookup(&lookup, self);
if (init_fn[0] != MP_OBJ_NULL) {
mp_obj_t init_ret;
if (n_args == 0 && n_kw == 0) {
@ -299,7 +323,13 @@ STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) {
}
*/
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, op_name, offsetof(mp_obj_type_t, unary_op), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = op_name,
.meth_offset = offsetof(mp_obj_type_t, unary_op),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_SENTINEL) {
return mp_unary_op(op, self->subobj[0]);
} else if (member[0] != MP_OBJ_NULL) {
@ -386,7 +416,13 @@ STATIC mp_obj_t instance_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
*/
mp_obj_t dest[3] = {MP_OBJ_NULL};
mp_obj_class_lookup(lhs, lhs->base.type, op_name, offsetof(mp_obj_type_t, binary_op), dest);
struct class_lookup_data lookup = {
.obj = lhs,
.attr = op_name,
.meth_offset = offsetof(mp_obj_type_t, binary_op),
.dest = dest,
};
mp_obj_class_lookup(&lookup, lhs->base.type);
if (dest[0] == MP_OBJ_SENTINEL) {
return mp_binary_op(op, lhs->subobj[0], rhs_in);
} else if (dest[0] != MP_OBJ_NULL) {
@ -410,7 +446,13 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return;
}
mp_obj_class_lookup(self, self->base.type, attr, 0, dest);
struct class_lookup_data lookup = {
.obj = self,
.attr = attr,
.meth_offset = 0,
.dest = dest,
};
mp_obj_class_lookup(&lookup, self->base.type);
mp_obj_t member = dest[0];
if (member != MP_OBJ_NULL) {
#if MICROPY_PY_BUILTINS_PROPERTY
@ -451,7 +493,13 @@ STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
// for property, we need to do a lookup first in the class dict
// this makes all stores slow... how to fix?
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, attr, 0, member);
struct class_lookup_data lookup = {
.obj = self,
.attr = attr,
.meth_offset = 0,
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] != MP_OBJ_NULL && MP_OBJ_IS_TYPE(member[0], &mp_type_property)) {
// attribute already exists and is a property
// delegate the store to the property
@ -481,18 +529,26 @@ STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
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};
struct class_lookup_data lookup = {
.obj = self,
.meth_offset = offsetof(mp_obj_type_t, subscr),
.dest = member,
};
uint meth_args;
if (value == MP_OBJ_NULL) {
// delete item
mp_obj_class_lookup(self, self->base.type, MP_QSTR___delitem__, offsetof(mp_obj_type_t, subscr), member);
lookup.attr = MP_QSTR___delitem__;
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 2;
} else if (value == MP_OBJ_SENTINEL) {
// load item
mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, offsetof(mp_obj_type_t, subscr), member);
lookup.attr = MP_QSTR___getitem__;
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 2;
} else {
// store item
mp_obj_class_lookup(self, self->base.type, MP_QSTR___setitem__, offsetof(mp_obj_type_t, subscr), member);
lookup.attr = MP_QSTR___setitem__;
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 3;
}
if (member[0] == MP_OBJ_SENTINEL) {
@ -514,7 +570,13 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_instance_t *self = self_in;
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, MP_QSTR___call__, offsetof(mp_obj_type_t, call), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR___call__,
.meth_offset = offsetof(mp_obj_type_t, call),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in)));
}
@ -528,10 +590,18 @@ STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp
STATIC mp_obj_t instance_getiter(mp_obj_t self_in) {
mp_obj_instance_t *self = self_in;
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, MP_QSTR___iter__, offsetof(mp_obj_type_t, getiter), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR___iter__,
.meth_offset = offsetof(mp_obj_type_t, getiter),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_NULL) {
// This kinda duplicates code in mp_getiter()
mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, 0, member);
lookup.attr = MP_QSTR___getitem__;
lookup.meth_offset = 0; // TODO
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] != MP_OBJ_NULL) {
// __getitem__ exists, create an iterator
return mp_obj_new_getitem_iter(member);
@ -601,7 +671,13 @@ STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return;
}
#endif
mp_obj_class_lookup(NULL, self, attr, 0, dest);
struct class_lookup_data lookup = {
.obj = NULL,
.attr = attr,
.meth_offset = 0,
.dest = dest,
};
mp_obj_class_lookup(&lookup, self);
}
STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
@ -740,14 +816,20 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
uint len;
mp_obj_t *items;
mp_obj_tuple_get(type->bases_tuple, &len, &items);
struct class_lookup_data lookup = {
.obj = self->obj,
.attr = attr,
.meth_offset = 0,
.dest = dest,
};
for (uint i = 0; i < len; i++) {
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, dest);
mp_obj_class_lookup(&lookup, (mp_obj_type_t*)items[i]);
if (dest[0] != MP_OBJ_NULL) {
return;
}
}
mp_obj_class_lookup(self->obj, &mp_type_object, attr, 0, dest);
mp_obj_class_lookup(&lookup, &mp_type_object);
}
const mp_obj_type_t mp_type_super = {