diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/builtinhelp.c | 4 | ||||
-rw-r--r-- | py/dynruntime.h | 2 | ||||
-rw-r--r-- | py/modbuiltins.c | 2 | ||||
-rw-r--r-- | py/obj.c | 28 | ||||
-rw-r--r-- | py/obj.h | 12 | ||||
-rw-r--r-- | py/objarray.c | 2 | ||||
-rw-r--r-- | py/objnamedtuple.c | 14 | ||||
-rw-r--r-- | py/objtuple.c | 4 | ||||
-rw-r--r-- | py/objtype.c | 136 | ||||
-rw-r--r-- | py/opmethods.c | 12 | ||||
-rw-r--r-- | py/runtime.c | 59 | ||||
-rw-r--r-- | py/stream.c | 25 | ||||
-rw-r--r-- | py/stream.h | 2 |
13 files changed, 160 insertions, 142 deletions
diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 94f8beaff2..93d94a389d 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -143,8 +143,8 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) { if (type == &mp_type_type) { type = MP_OBJ_TO_PTR(obj); } - if (type->locals_dict != NULL) { - map = &type->locals_dict->map; + if (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) { + map = &MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->map; } } if (map != NULL) { diff --git a/py/dynruntime.h b/py/dynruntime.h index fb748eb93f..be573bde2a 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -150,7 +150,7 @@ static inline mp_obj_t mp_obj_cast_to_native_base_dyn(mp_obj_t self_in, mp_const if (MP_OBJ_FROM_PTR(self_type) == native_type) { return self_in; - } else if (self_type->parent != native_type) { + } else if (MP_OBJ_TYPE_GET_SLOT_OR_NULL(self_type, parent) != native_type) { // The self_in object is not a direct descendant of native_type, so fail the cast. // This is a very simple version of mp_obj_is_subclass_fast that could be improved. return MP_OBJ_NULL; diff --git a/py/modbuiltins.c b/py/modbuiltins.c index f74db95cf5..152323b5ca 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -455,7 +455,7 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) { #if MICROPY_CAN_OVERRIDE_BUILTINS // Set "_" special variable mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o}; - mp_type_module.attr(MP_OBJ_FROM_PTR(&mp_module_builtins), MP_QSTR__, dest); + MP_OBJ_TYPE_GET_SLOT(&mp_type_module, attr)(MP_OBJ_FROM_PTR(&mp_module_builtins), MP_QSTR__, dest); #endif } return mp_const_none; @@ -116,8 +116,8 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t } #endif const mp_obj_type_t *type = mp_obj_get_type(o_in); - if (type->print != NULL) { - type->print((mp_print_t *)print, o_in, kind); + if (MP_OBJ_TYPE_HAS_SLOT(type, print)) { + MP_OBJ_TYPE_GET_SLOT(type, print)((mp_print_t *)print, o_in, kind); } else { mp_printf(print, "<%q>", type->name); } @@ -170,8 +170,8 @@ bool mp_obj_is_true(mp_obj_t arg) { } } else { const mp_obj_type_t *type = mp_obj_get_type(arg); - if (type->unary_op != NULL) { - mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg); + if (MP_OBJ_TYPE_HAS_SLOT(type, unary_op)) { + mp_obj_t result = MP_OBJ_TYPE_GET_SLOT(type, unary_op)(MP_UNARY_OP_BOOL, arg); if (result != MP_OBJ_NULL) { return result == mp_const_true; } @@ -189,7 +189,7 @@ bool mp_obj_is_true(mp_obj_t arg) { } bool mp_obj_is_callable(mp_obj_t o_in) { - const mp_call_fun_t call = mp_obj_get_type(o_in)->call; + const mp_call_fun_t call = MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o_in), call); if (call != mp_obj_instance_call) { return call != NULL; } @@ -256,19 +256,19 @@ mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) { const mp_obj_type_t *type = mp_obj_get_type(o1); // If a full equality test is not needed and the other object is a different // type then we don't need to bother trying the comparison. - if (type->binary_op != NULL && + if (MP_OBJ_TYPE_HAS_SLOT(type, binary_op) && ((type->flags & MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) || mp_obj_get_type(o2) == type)) { // CPython is asymmetric: it will try __eq__ if there's no __ne__ but not the // other way around. If the class doesn't need a full test we can skip __ne__. if (op == MP_BINARY_OP_NOT_EQUAL && (type->flags & MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)) { - mp_obj_t r = type->binary_op(MP_BINARY_OP_NOT_EQUAL, o1, o2); + mp_obj_t r = MP_OBJ_TYPE_GET_SLOT(type, binary_op)(MP_BINARY_OP_NOT_EQUAL, o1, o2); if (r != MP_OBJ_NULL) { return r; } } // Try calling __eq__. - mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); + mp_obj_t r = MP_OBJ_TYPE_GET_SLOT(type, binary_op)(MP_BINARY_OP_EQUAL, o1, o2); if (r != MP_OBJ_NULL) { if (op == MP_BINARY_OP_EQUAL) { return r; @@ -524,8 +524,8 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { return MP_OBJ_NEW_SMALL_INT(l); } else { const mp_obj_type_t *type = mp_obj_get_type(o_in); - if (type->unary_op != NULL) { - return type->unary_op(MP_UNARY_OP_LEN, o_in); + if (MP_OBJ_TYPE_HAS_SLOT(type, unary_op)) { + return MP_OBJ_TYPE_GET_SLOT(type, unary_op)(MP_UNARY_OP_LEN, o_in); } else { return MP_OBJ_NULL; } @@ -534,8 +534,8 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { const mp_obj_type_t *type = mp_obj_get_type(base); - if (type->subscr != NULL) { - mp_obj_t ret = type->subscr(base, index, value); + if (MP_OBJ_TYPE_HAS_SLOT(type, subscr)) { + mp_obj_t ret = MP_OBJ_TYPE_GET_SLOT(type, subscr)(base, index, value); if (ret != MP_OBJ_NULL) { return ret; } @@ -579,10 +579,10 @@ mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) { bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { const mp_obj_type_t *type = mp_obj_get_type(obj); - if (type->buffer == NULL) { + if (!MP_OBJ_TYPE_HAS_SLOT(type, buffer)) { return false; } - int ret = type->buffer(obj, bufinfo, flags); + int ret = MP_OBJ_TYPE_GET_SLOT(type, buffer)(obj, bufinfo, flags); if (ret != 0) { return false; } @@ -660,6 +660,16 @@ typedef mp_obj_type_t mp_obj_full_type_t; #define MP_DEFINE_CONST_OBJ_TYPE_NARGS_11(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .f1 = v1, .f2 = v2, .f3 = v3, .f4 = v4, .f5 = v5, .f6 = v6, .f7 = v7, .f8 = v8, .f9 = v9, .f10 = v10, .f11 = v11 } #define MP_DEFINE_CONST_OBJ_TYPE_NARGS_12(_struct_type, _typename, _name, _flags, _make_new, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8, f9, v9, f10, v10, f11, v11, f12, v12) const _struct_type _typename = { .base = { &mp_type_type }, .name = _name, .flags = _flags, .make_new = _make_new, .f1 = v1, .f2 = v2, .f3 = v3, .f4 = v4, .f5 = v5, .f6 = v6, .f7 = v7, .f8 = v8, .f9 = v9, .f10 = v10, .f11 = v11, .f12 = v12 } +// Always safe, checks if the type can and does have this slot. +#define MP_OBJ_TYPE_HAS_SLOT(t, f) ((t)->f) +// Requires you know that this type can have this slot. +#define MP_OBJ_TYPE_GET_SLOT(t, f) ((t)->f) +// Always safe, returns NULL if the type cannot have this slot. +#define MP_OBJ_TYPE_GET_SLOT_OR_NULL(t, f) ((t)->f) +#define MP_OBJ_TYPE_SET_SLOT(t, f, v, n) ((t)->f = v) +#define MP_OBJ_TYPE_OFFSETOF_SLOT(f) (offsetof(mp_obj_type_t, f)) +#define MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(t, offset) (*(void **)((char *)(t) + (offset)) != NULL) + // Workaround for https://docs.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-160#macro-arguments-are-unpacked #define MP_DEFINE_CONST_OBJ_TYPE_EXPAND(x) x @@ -822,7 +832,7 @@ void *mp_obj_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); #endif #define mp_obj_is_int(o) (mp_obj_is_small_int(o) || mp_obj_is_exact_type(o, &mp_type_int)) #define mp_obj_is_str(o) (mp_obj_is_qstr(o) || mp_obj_is_exact_type(o, &mp_type_str)) -#define mp_obj_is_str_or_bytes(o) (mp_obj_is_qstr(o) || (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) +#define mp_obj_is_str_or_bytes(o) (mp_obj_is_qstr(o) || (mp_obj_is_obj(o) && MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type, binary_op) == mp_obj_str_binary_op)) #define mp_obj_is_dict_or_ordereddict(o) (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->make_new == mp_obj_dict_make_new) #define mp_obj_is_fun(o) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) diff --git a/py/objarray.c b/py/objarray.c index 1cb163c4b9..762a4105c5 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -443,7 +443,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value size_t src_len; void *src_items; size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); - if (mp_obj_is_obj(value) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { + if (mp_obj_is_obj(value) && MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type, subscr) == array_subscr) { // value is array, bytearray or memoryview mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index b212993506..cc55aec0b9 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -157,14 +157,14 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t o->base.base.type = &mp_type_type; o->base.flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE; // can match tuple o->base.name = name; - o->base.print = namedtuple_print; 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.attr = namedtuple_attr; - o->base.subscr = mp_obj_tuple_subscr; - o->base.getiter = mp_obj_tuple_getiter; - o->base.parent = &mp_type_tuple; + MP_OBJ_TYPE_SET_SLOT(&o->base, print, namedtuple_print, 0); + MP_OBJ_TYPE_SET_SLOT(&o->base, unary_op, mp_obj_tuple_unary_op, 1); + MP_OBJ_TYPE_SET_SLOT(&o->base, binary_op, mp_obj_tuple_binary_op, 2); + MP_OBJ_TYPE_SET_SLOT(&o->base, attr, namedtuple_attr, 3); + MP_OBJ_TYPE_SET_SLOT(&o->base, subscr, mp_obj_tuple_subscr, 4); + MP_OBJ_TYPE_SET_SLOT(&o->base, getiter, mp_obj_tuple_getiter, 5); + MP_OBJ_TYPE_SET_SLOT(&o->base, parent, &mp_type_tuple, 6); return MP_OBJ_FROM_PTR(o); } diff --git a/py/objtuple.c b/py/objtuple.c index a684b13e6f..01b2fa1488 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -32,7 +32,7 @@ #include "py/runtime.h" // type check is done on getiter method to allow tuple, namedtuple, attrtuple -#define mp_obj_is_tuple_compatible(o) (mp_obj_get_type(o)->getiter == mp_obj_tuple_getiter) +#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), getiter) == mp_obj_tuple_getiter) /******************************************************************************/ /* tuple */ @@ -111,7 +111,7 @@ STATIC mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t anothe mp_check_self(mp_obj_is_tuple_compatible(self_in)); const mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); - if (another_type->getiter != mp_obj_tuple_getiter) { + if (MP_OBJ_TYPE_GET_SLOT_OR_NULL(another_type, getiter) != mp_obj_tuple_getiter) { // Slow path for user subclasses another_in = mp_obj_cast_to_native_base(another_in, MP_OBJ_FROM_PTR(&mp_type_tuple)); if (another_in == MP_OBJ_NULL) { diff --git a/py/objtype.c b/py/objtype.c index cc5a5e5802..968d6eb3ac 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -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)); } } } diff --git a/py/opmethods.c b/py/opmethods.c index 595cc088ba..c3931fd358 100644 --- a/py/opmethods.c +++ b/py/opmethods.c @@ -29,24 +29,28 @@ STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) { const mp_obj_type_t *type = mp_obj_get_type(self_in); - return type->subscr(self_in, key_in, MP_OBJ_SENTINEL); + // Note: assumes type must have subscr (only used by dict). + return MP_OBJ_TYPE_GET_SLOT(type, subscr)(self_in, key_in, MP_OBJ_SENTINEL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_getitem_obj, op_getitem); STATIC mp_obj_t op_setitem(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { const mp_obj_type_t *type = mp_obj_get_type(self_in); - return type->subscr(self_in, key_in, value_in); + // Note: assumes type must have subscr (only used by dict). + return MP_OBJ_TYPE_GET_SLOT(type, subscr)(self_in, key_in, value_in); } MP_DEFINE_CONST_FUN_OBJ_3(mp_op_setitem_obj, op_setitem); STATIC mp_obj_t op_delitem(mp_obj_t self_in, mp_obj_t key_in) { const mp_obj_type_t *type = mp_obj_get_type(self_in); - return type->subscr(self_in, key_in, MP_OBJ_NULL); + // Note: assumes type must have subscr (only used by dict). + return MP_OBJ_TYPE_GET_SLOT(type, subscr)(self_in, key_in, MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem); STATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) { const mp_obj_type_t *type = mp_obj_get_type(lhs_in); - return type->binary_op(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in); + // Note: assumes type must have binary_op (only used by set/frozenset). + return MP_OBJ_TYPE_GET_SLOT(type, binary_op)(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains); diff --git a/py/runtime.c b/py/runtime.c index 27b4f05f04..d0e504a3d0 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -307,8 +307,8 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { return MP_OBJ_NEW_SMALL_INT(h); } else { const mp_obj_type_t *type = mp_obj_get_type(arg); - if (type->unary_op != NULL) { - mp_obj_t result = type->unary_op(op, arg); + if (MP_OBJ_TYPE_HAS_SLOT(type, unary_op)) { + mp_obj_t result = MP_OBJ_TYPE_GET_SLOT(type, unary_op)(op, arg); if (result != MP_OBJ_NULL) { return result; } @@ -613,8 +613,8 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs const mp_obj_type_t *type; generic_binary_op: type = mp_obj_get_type(lhs); - if (type->binary_op != NULL) { - mp_obj_t result = type->binary_op(op, lhs, rhs); + if (MP_OBJ_TYPE_HAS_SLOT(type, binary_op)) { + mp_obj_t result = MP_OBJ_TYPE_GET_SLOT(type, binary_op)(op, lhs, rhs); if (result != MP_OBJ_NULL) { return result; } @@ -689,8 +689,8 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons const mp_obj_type_t *type = mp_obj_get_type(fun_in); // do the call - if (type->call != NULL) { - return type->call(fun_in, n_args, n_kw, args); + if (MP_OBJ_TYPE_HAS_SLOT(type, call)) { + return MP_OBJ_TYPE_GET_SLOT(type, call)(fun_in, n_args, n_kw, args); } #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE @@ -1167,14 +1167,14 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { } #endif - if (attr == MP_QSTR___next__ && type->iternext != NULL) { + if (attr == MP_QSTR___next__ && MP_OBJ_TYPE_HAS_SLOT(type, iternext)) { dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj); dest[1] = obj; return; } - if (type->attr != NULL) { + if (MP_OBJ_TYPE_HAS_SLOT(type, attr)) { // this type can do its own load, so call it - type->attr(obj, attr, dest); + MP_OBJ_TYPE_GET_SLOT(type, attr)(obj, attr, dest); // If type->attr has set dest[1] = MP_OBJ_SENTINEL, we should proceed // with lookups below (i.e. in locals_dict). If not, return right away. if (dest[1] != MP_OBJ_SENTINEL) { @@ -1183,11 +1183,11 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { // Clear the fail flag set by type->attr so it's like it never ran. dest[1] = MP_OBJ_NULL; } - if (type->locals_dict != NULL) { + if (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) { // generic method lookup // this is a lookup in the object (ie not class or type) - assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now - mp_map_t *locals_map = &type->locals_dict->map; + assert(MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->base.type == &mp_type_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(attr), MP_MAP_LOOKUP); if (elem != NULL) { mp_convert_member_lookup(obj, type, elem->value, dest); @@ -1239,9 +1239,9 @@ void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catc 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); const mp_obj_type_t *type = mp_obj_get_type(base); - if (type->attr != NULL) { + if (MP_OBJ_TYPE_HAS_SLOT(type, attr)) { mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value}; - type->attr(base, attr, dest); + MP_OBJ_TYPE_GET_SLOT(type, attr)(base, attr, dest); if (dest[0] == MP_OBJ_NULL) { // success return; @@ -1260,20 +1260,21 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { assert(o_in); const mp_obj_type_t *type = mp_obj_get_type(o_in); - // Check for native getiter which is the identity. We handle this case explicitly - // so we don't unnecessarily allocate any RAM for the iter_buf, which won't be used. - if (type->getiter == mp_identity_getiter) { - return o_in; - } - // check for native getiter (corresponds to __iter__) - if (type->getiter != NULL) { - if (iter_buf == NULL && type->getiter != mp_obj_instance_getiter) { + if (MP_OBJ_TYPE_HAS_SLOT(type, getiter)) { + // Check for native getiter which is the identity. We handle this case explicitly + // so we don't unnecessarily allocate any RAM for the iter_buf, which won't be used. + if (MP_OBJ_TYPE_GET_SLOT(type, getiter) == mp_identity_getiter) { + return o_in; + } + + // check for native getiter (corresponds to __iter__) + if (iter_buf == NULL && MP_OBJ_TYPE_GET_SLOT(type, getiter) != mp_obj_instance_getiter) { // if caller did not provide a buffer then allocate one on the heap // mp_obj_instance_getiter is special, it will allocate only if needed iter_buf = m_new_obj(mp_obj_iter_buf_t); } - mp_obj_t iter = type->getiter(o_in, iter_buf); + mp_obj_t iter = MP_OBJ_TYPE_GET_SLOT(type, getiter)(o_in, iter_buf); if (iter != MP_OBJ_NULL) { return iter; } @@ -1305,9 +1306,9 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { // may also raise StopIteration() mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { const mp_obj_type_t *type = mp_obj_get_type(o_in); - if (type->iternext != NULL) { + if (MP_OBJ_TYPE_HAS_SLOT(type, iternext)) { MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL; - return type->iternext(o_in); + return MP_OBJ_TYPE_GET_SLOT(type, iternext)(o_in); } else { // check for __next__ method mp_obj_t dest[2]; @@ -1331,9 +1332,9 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { mp_obj_t mp_iternext(mp_obj_t o_in) { MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext const mp_obj_type_t *type = mp_obj_get_type(o_in); - if (type->iternext != NULL) { + if (MP_OBJ_TYPE_HAS_SLOT(type, iternext)) { MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL; - return type->iternext(o_in); + return MP_OBJ_TYPE_GET_SLOT(type, iternext)(o_in); } else { // check for __next__ method mp_obj_t dest[2]; @@ -1371,9 +1372,9 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val); } - if (type->iternext != NULL && send_value == mp_const_none) { + if (MP_OBJ_TYPE_HAS_SLOT(type, iternext) && send_value == mp_const_none) { MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL; - mp_obj_t ret = type->iternext(self_in); + mp_obj_t ret = MP_OBJ_TYPE_GET_SLOT(type, iternext)(self_in); *ret_val = ret; if (ret != MP_OBJ_STOP_ITERATION) { return MP_VM_RETURN_YIELD; diff --git a/py/stream.c b/py/stream.c index 87bed38f67..36325e7d41 100644 --- a/py/stream.c +++ b/py/stream.c @@ -84,15 +84,16 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { const mp_obj_type_t *type = mp_obj_get_type(self_in); - const mp_stream_p_t *stream_p = type->protocol; - if (stream_p == NULL - || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) - || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) - || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { - // CPython: io.UnsupportedOperation, OSError subclass - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("stream operation not supported")); + if (MP_OBJ_TYPE_HAS_SLOT(type, protocol)) { + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(type, protocol); + if (!((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) + && !((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) + && !((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { + return stream_p; + } } - return stream_p; + // CPython: io.UnsupportedOperation, OSError subclass + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("stream operation not supported")); } STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { @@ -517,7 +518,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj, 2, 3, stream_ioctl); ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) { mp_obj_base_t *o = stream; - const mp_stream_p_t *stream_p = o->type->protocol; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &errno); if (out_sz == MP_STREAM_ERROR) { return -1; @@ -528,7 +529,7 @@ ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) { ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) { mp_obj_base_t *o = stream; - const mp_stream_p_t *stream_p = o->type->protocol; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &errno); if (out_sz == MP_STREAM_ERROR) { return -1; @@ -539,7 +540,7 @@ ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) { off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) { const mp_obj_base_t *o = stream; - const mp_stream_p_t *stream_p = o->type->protocol; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); struct mp_stream_seek_t seek_s; seek_s.offset = offset; seek_s.whence = whence; @@ -552,7 +553,7 @@ off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) { int mp_stream_posix_fsync(void *stream) { mp_obj_base_t *o = stream; - const mp_stream_p_t *stream_p = o->type->protocol; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &errno); if (res == MP_STREAM_ERROR) { return -1; diff --git a/py/stream.h b/py/stream.h index 45f36ef5a6..4bc329b3e7 100644 --- a/py/stream.h +++ b/py/stream.h @@ -95,7 +95,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); // Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) { - return (const mp_stream_p_t *)((const mp_obj_base_t *)MP_OBJ_TO_PTR(self))->type->protocol; + return (const mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(((const mp_obj_base_t *)MP_OBJ_TO_PTR(self))->type, protocol); } const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); |