summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2015-03-21 14:21:54 +0000
committerDamien George <damien.p.george@gmail.com>2015-03-21 14:21:54 +0000
commit55b74d1ff5fcdd32150b10cb42cd1fd59f1317c3 (patch)
tree6bcd00d3379aecc8b7a0012aac633b446c646768 /py
parent59f68313369802a9fe19c5161891075d5163c0f0 (diff)
downloadmicropython-55b74d1ff5fcdd32150b10cb42cd1fd59f1317c3.tar.gz
micropython-55b74d1ff5fcdd32150b10cb42cd1fd59f1317c3.zip
py: Combine duplicated code that converts members from a lookup.
Despite initial guess, this code factoring does not hamper performance. In fact it seems to improve speed by a little: running pystone(1.2) on pyboard (which gives a very stable result) this patch takes pystones from 1729.51 up to 1742.16. Also, pystones on x64 increase by around the same proportion (but it's much noisier). Taking a look at the generated machine code, stack usage with this patch is unchanged, and call is tail-optimised with all arguments in registers. Code size decreases by about 50 bytes on Thumb2 archs.
Diffstat (limited to 'py')
-rw-r--r--py/objtype.c38
-rw-r--r--py/runtime.c46
-rw-r--r--py/runtime.h1
3 files changed, 32 insertions, 53 deletions
diff --git a/py/objtype.c b/py/objtype.c
index 8855777490..f64e5054ad 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -51,7 +51,6 @@ STATIC mp_obj_t static_class_method_make_new(mp_obj_t self_in, mp_uint_t n_args,
#define is_instance_type(type) ((type)->make_new == instance_make_new)
#define is_native_type(type) ((type)->make_new != instance_make_new)
mp_obj_t instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
-STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) {
mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs);
@@ -129,19 +128,18 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
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(lookup->attr), MP_MAP_LOOKUP);
if (elem != NULL) {
- lookup->dest[0] = elem->value;
if (lookup->is_type) {
// If we look up a class method, we need to return original type for which we
// do a lookup, not a (base) type in which we found the class method.
const mp_obj_type_t *org_type = (const mp_obj_type_t*)lookup->obj;
- instance_convert_return_attr(NULL, org_type, elem->value, lookup->dest);
+ mp_convert_member_lookup(NULL, org_type, elem->value, lookup->dest);
} else {
mp_obj_instance_t *obj = lookup->obj;
if (obj != MP_OBJ_NULL && is_native_type(type) && type != &mp_type_object /* object is not a real type */) {
// If we're dealing with native base class, then it applies to native sub-object
obj = obj->subobj[0];
}
- instance_convert_return_attr(obj, type, elem->value, lookup->dest);
+ mp_convert_member_lookup(obj, type, elem->value, lookup->dest);
}
#if DEBUG_PRINT
printf("mp_obj_class_lookup: Returning: ");
@@ -411,32 +409,6 @@ const qstr mp_binary_op_method_name[] = {
[MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size
};
-// Given a member that was extracted from an instance, convert it correctly
-// and put the result in the dest[] array for a possible method call.
-// Conversion means dealing with static/class methods, callables, and values.
-// see http://docs.python.org/3/howto/descriptor.html
-STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) {
- assert(dest[1] == NULL);
- if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) {
- // return just the function
- dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
- } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) {
- // return a bound method, with self being the type of this object
- dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
- dest[1] = (mp_obj_t)type;
- } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) {
- // Don't try to bind types (even though they're callable)
- dest[0] = member;
- } else if (mp_obj_is_callable(member)) {
- // return a bound method, with self being this object
- dest[0] = member;
- dest[1] = self;
- } else {
- // class member is a value, so just return that value
- dest[0] = member;
- }
-}
-
STATIC mp_obj_t instance_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// Note: For ducktyping, CPython does not look in the instance members or use
// __getattr__ or __getattribute__. It only looks in the class dictionary.
@@ -493,13 +465,13 @@ void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
// object member is a property
// delegate the store to the property
- // TODO should this be part of instance_convert_return_attr?
+ // TODO should this be part of mp_convert_member_lookup?
const mp_obj_t *proxy = mp_obj_property_get(member);
if (proxy[0] == mp_const_none) {
// TODO
} else {
dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
- // TODO should we convert the returned value using instance_convert_return_attr?
+ // TODO should we convert the returned value using mp_convert_member_lookup?
}
}
#endif
@@ -591,7 +563,7 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
return mp_obj_subscr(self->subobj[0], index, value);
} else if (member[0] != MP_OBJ_NULL) {
mp_obj_t args[3] = {self_in, index, value};
- // TODO probably need to call instance_convert_return_attr, and use mp_call_method_n_kw
+ // TODO probably need to call mp_convert_member_lookup, and use mp_call_method_n_kw
mp_obj_t ret = mp_call_function_n_kw(member[0], meth_args, 0, args);
if (value == MP_OBJ_SENTINEL) {
return ret;
diff --git a/py/runtime.c b/py/runtime.c
index f1633c6c54..0ff78b2a96 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -854,6 +854,31 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) {
}
}
+// Given a member that was extracted from an instance, convert it correctly
+// and put the result in the dest[] array for a possible method call.
+// Conversion means dealing with static/class methods, callables, and values.
+// see http://docs.python.org/3/howto/descriptor.html
+void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) {
+ if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) {
+ // return just the function
+ dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
+ } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) {
+ // return a bound method, with self being the type of this object
+ dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
+ dest[1] = (mp_obj_t)type;
+ } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) {
+ // Don't try to bind types (even though they're callable)
+ dest[0] = member;
+ } else if (mp_obj_is_callable(member)) {
+ // return a bound method, with self being this object
+ dest[0] = member;
+ dest[1] = self;
+ } else {
+ // class member is a value, so just return that value
+ dest[0] = member;
+ }
+}
+
// no attribute found, returns: dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL
// normal attribute found, returns: dest[0] == <attribute>, dest[1] == MP_OBJ_NULL
// method attribute found, returns: dest[0] == <method>, dest[1] == <self>
@@ -888,26 +913,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
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);
if (elem != NULL) {
- // check if the methods are functions, static or class methods
- // see http://docs.python.org/3/howto/descriptor.html
- if (MP_OBJ_IS_TYPE(elem->value, &mp_type_staticmethod)) {
- // return just the function
- dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
- } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_classmethod)) {
- // return a bound method, with self being the type of this object
- dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
- dest[1] = type;
- } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_type)) {
- // Don't try to bind types
- dest[0] = elem->value;
- } else if (mp_obj_is_callable(elem->value)) {
- // return a bound method, with self being this object
- dest[0] = elem->value;
- dest[1] = obj;
- } else {
- // class member is a value, so just return that value
- dest[0] = elem->value;
- }
+ mp_convert_member_lookup(obj, type, elem->value, dest);
}
}
}
diff --git a/py/runtime.h b/py/runtime.h
index e09162433d..bead02831a 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -101,6 +101,7 @@ void mp_unpack_sequence(mp_obj_t seq, mp_uint_t num, mp_obj_t *items);
void mp_unpack_ex(mp_obj_t seq, mp_uint_t num, mp_obj_t *items);
mp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value);
mp_obj_t mp_load_attr(mp_obj_t base, qstr attr);
+void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest);
void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest);
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val);