LCOV - code coverage report
Current view: top level - py - objtype.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-724-gfb7d21153.info Lines: 566 566 100.0 %
Date: 2022-12-01 09:37:31 Functions: 33 33 100.0 %
Branches: 381 446 85.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2013-2018 Damien P. George
       7                 :            :  * Copyright (c) 2014-2018 Paul Sokolovsky
       8                 :            :  *
       9                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      10                 :            :  * of this software and associated documentation files (the "Software"), to deal
      11                 :            :  * in the Software without restriction, including without limitation the rights
      12                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13                 :            :  * copies of the Software, and to permit persons to whom the Software is
      14                 :            :  * furnished to do so, subject to the following conditions:
      15                 :            :  *
      16                 :            :  * The above copyright notice and this permission notice shall be included in
      17                 :            :  * all copies or substantial portions of the Software.
      18                 :            :  *
      19                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      25                 :            :  * THE SOFTWARE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include <stdio.h>
      29                 :            : #include <stddef.h>
      30                 :            : #include <string.h>
      31                 :            : #include <assert.h>
      32                 :            : 
      33                 :            : #include "py/objtype.h"
      34                 :            : #include "py/runtime.h"
      35                 :            : 
      36                 :            : #if MICROPY_DEBUG_VERBOSE // print debugging info
      37                 :            : #define DEBUG_PRINT (1)
      38                 :            : #define DEBUG_printf DEBUG_printf
      39                 :            : #else // don't print debugging info
      40                 :            : #define DEBUG_PRINT (0)
      41                 :            : #define DEBUG_printf(...) (void)0
      42                 :            : #endif
      43                 :            : 
      44                 :            : #define ENABLE_SPECIAL_ACCESSORS \
      45                 :            :     (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY)
      46                 :            : 
      47                 :            : STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
      48                 :            : 
      49                 :            : /******************************************************************************/
      50                 :            : // instance object
      51                 :            : 
      52                 :       4065 : STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
      53                 :       4065 :     int count = 0;
      54                 :       5330 :     for (;;) {
      55         [ +  + ]:       5330 :         if (type == &mp_type_object) {
      56                 :            :             // Not a "real" type, end search here.
      57                 :            :             return count;
      58         [ +  + ]:       4854 :         } else if (mp_obj_is_native_type(type)) {
      59                 :            :             // Native types don't have parents (at least not from our perspective) so end.
      60                 :        683 :             *last_native_base = type;
      61                 :        683 :             return count + 1;
      62         [ +  + ]:       4171 :         } else if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
      63                 :            :             // No parents so end search here.
      64                 :            :             return count;
      65                 :            :         #if MICROPY_MULTIPLE_INHERITANCE
      66         [ +  + ]:       1389 :         } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
      67                 :            :             // Multiple parents, search through them all recursively.
      68                 :        124 :             const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
      69                 :        124 :             const mp_obj_t *item = parent_tuple->items;
      70                 :        124 :             const mp_obj_t *top = item + parent_tuple->len;
      71         [ +  + ]:        372 :             for (; item < top; ++item) {
      72   [ +  -  -  + ]:        248 :                 assert(mp_obj_is_type(*item, &mp_type_type));
      73                 :        248 :                 const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
      74                 :        248 :                 count += instance_count_native_bases(bt, last_native_base);
      75                 :            :             }
      76                 :            :             return count;
      77                 :            :         #endif
      78                 :            :         } else {
      79                 :            :             // A single parent, use iteration to continue the search.
      80                 :            :             type = MP_OBJ_TYPE_GET_SLOT(type, parent);
      81                 :            :         }
      82                 :            :     }
      83                 :            : }
      84                 :            : 
      85                 :            : // This wrapper function is allows a subclass of a native type to call the
      86                 :            : // __init__() method (corresponding to type->make_new) of the native type.
      87                 :         10 : STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) {
      88                 :         10 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]);
      89                 :         10 :     const mp_obj_type_t *native_base = NULL;
      90                 :         10 :     instance_count_native_bases(self->base.type, &native_base);
      91                 :         10 :     self->subobj[0] = MP_OBJ_TYPE_GET_SLOT(native_base, make_new)(native_base, n_args - 1, 0, args + 1);
      92                 :         10 :     return mp_const_none;
      93                 :            : }
      94                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper);
      95                 :            : 
      96                 :            : #if !MICROPY_CPYTHON_COMPAT
      97                 :            : STATIC
      98                 :            : #endif
      99                 :       2315 : mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) {
     100                 :       2315 :     size_t num_native_bases = instance_count_native_bases(class, native_base);
     101         [ -  + ]:       2315 :     assert(num_native_bases < 2);
     102                 :       2315 :     mp_obj_instance_t *o = mp_obj_malloc_var(mp_obj_instance_t, mp_obj_t, num_native_bases, class);
     103                 :       2315 :     mp_map_init(&o->members, 0);
     104                 :            :     // Initialise the native base-class slot (should be 1 at most) with a valid
     105                 :            :     // object.  It doesn't matter which object, so long as it can be uniquely
     106                 :            :     // distinguished from a native class that is initialised.
     107         [ +  + ]:       2315 :     if (num_native_bases != 0) {
     108                 :        378 :         o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
     109                 :            :     }
     110                 :       2315 :     return o;
     111                 :            : }
     112                 :            : 
     113                 :            : // TODO
     114                 :            : // This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO
     115                 :            : // http://python-history.blogspot.com/2010/06/method-resolution-order.html
     116                 :            : // https://www.python.org/download/releases/2.3/mro/
     117                 :            : //
     118                 :            : // will keep lookup->dest[0]'s value (should be MP_OBJ_NULL on invocation) if attribute
     119                 :            : // is not found
     120                 :            : // will set lookup->dest[0] to MP_OBJ_SENTINEL if special method was found in a native
     121                 :            : // type base via slot id (as specified by lookup->slot_offset). As there can be only one
     122                 :            : // native base, it's known that it applies to instance->subobj[0]. In most cases, we also
     123                 :            : // don't need to know which type it was - because instance->subobj[0] is of that type.
     124                 :            : // The only exception is when object is not yet constructed, then we need to know base
     125                 :            : // native type to construct its instance->subobj[0] from. But this case is handled via
     126                 :            : // instance_count_native_bases(), which returns a native base which it saw.
     127                 :            : struct class_lookup_data {
     128                 :            :     mp_obj_instance_t *obj;
     129                 :            :     qstr attr;
     130                 :            :     size_t slot_offset;
     131                 :            :     mp_obj_t *dest;
     132                 :            :     bool is_type;
     133                 :            : };
     134                 :            : 
     135                 :    1093298 : STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {
     136         [ -  + ]:    1093298 :     assert(lookup->dest[0] == MP_OBJ_NULL);
     137         [ -  + ]:    1093298 :     assert(lookup->dest[1] == MP_OBJ_NULL);
     138                 :    1120045 :     for (;;) {
     139                 :    1120045 :         DEBUG_printf("mp_obj_class_lookup: Looking up %s in %s\n", qstr_str(lookup->attr), qstr_str(type->name));
     140                 :            :         // Optimize special method lookup for native types
     141                 :            :         // This avoids extra method_name => slot lookup. On the other hand,
     142                 :            :         // this should not be applied to class types, as will result in extra
     143                 :            :         // lookup either.
     144   [ +  +  +  + ]:    1120045 :         if (lookup->slot_offset != 0 && mp_obj_is_native_type(type)) {
     145                 :            :             // Check if there is a non-zero value in the specified slot index,
     146                 :            :             // with a special case for getiter where the slot won't be set
     147                 :            :             // for MP_TYPE_FLAG_ITER_IS_STREAM.
     148   [ +  +  +  +  :        677 :             if (MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(type, lookup->slot_offset) || (lookup->slot_offset == MP_OBJ_TYPE_OFFSETOF_SLOT(iter) && type->flags & MP_TYPE_FLAG_ITER_IS_STREAM)) {
                   +  - ]
     149                 :        667 :                 DEBUG_printf("mp_obj_class_lookup: Matched special meth slot (off=%d) for %s\n",
     150                 :            :                     lookup->slot_offset, qstr_str(lookup->attr));
     151                 :        667 :                 lookup->dest[0] = MP_OBJ_SENTINEL;
     152                 :        667 :                 return;
     153                 :            :             }
     154                 :            :         }
     155                 :            : 
     156         [ +  + ]:    1119378 :         if (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) {
     157                 :            :             // search locals_dict (the set of methods/attributes)
     158         [ -  + ]:    1118983 :             assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(type, locals_dict)))); // MicroPython restriction, for now
     159                 :    1118984 :             mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->map;
     160                 :    1118984 :             mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
     161         [ +  + ]:    1118981 :             if (elem != NULL) {
     162         [ +  + ]:    1050384 :                 if (lookup->is_type) {
     163                 :            :                     // If we look up a class method, we need to return original type for which we
     164                 :            :                     // do a lookup, not a (base) type in which we found the class method.
     165                 :        711 :                     const mp_obj_type_t *org_type = (const mp_obj_type_t *)lookup->obj;
     166                 :        711 :                     mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest);
     167                 :            :                 } else {
     168                 :    1049673 :                     mp_obj_instance_t *obj = lookup->obj;
     169                 :    1049673 :                     mp_obj_t obj_obj;
     170   [ +  +  +  +  :    1049673 :                     if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {
                   +  + ]
     171                 :            :                         // If we're dealing with native base class, then it applies to native sub-object
     172                 :         26 :                         obj_obj = obj->subobj[0];
     173                 :            :                     } else {
     174                 :            :                         obj_obj = MP_OBJ_FROM_PTR(obj);
     175                 :            :                     }
     176                 :    1049673 :                     mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest);
     177                 :            :                 }
     178                 :            :                 #if DEBUG_PRINT
     179                 :            :                 DEBUG_printf("mp_obj_class_lookup: Returning: ");
     180                 :            :                 mp_obj_print_helper(MICROPY_DEBUG_PRINTER, lookup->dest[0], PRINT_REPR);
     181                 :            :                 if (lookup->dest[1] != MP_OBJ_NULL) {
     182                 :            :                     // Don't try to repr() lookup->dest[1], as we can be called recursively
     183                 :            :                     DEBUG_printf(" <%s @%p>", mp_obj_get_type_str(lookup->dest[1]), MP_OBJ_TO_PTR(lookup->dest[1]));
     184                 :            :                 }
     185                 :            :                 DEBUG_printf("\n");
     186                 :            :                 #endif
     187                 :    1050385 :                 return;
     188                 :            :             }
     189                 :            :         }
     190                 :            : 
     191                 :            :         // Previous code block takes care about attributes defined in .locals_dict,
     192                 :            :         // but some attributes of native types may be handled using .load_attr method,
     193                 :            :         // so make sure we try to lookup those too.
     194   [ +  +  +  +  :      68992 :         if (lookup->obj != NULL && !lookup->is_type && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {
             +  +  +  - ]
     195                 :        476 :             mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest);
     196         [ +  + ]:        476 :             if (lookup->dest[0] != MP_OBJ_NULL) {
     197                 :            :                 return;
     198                 :            :             }
     199                 :            :         }
     200                 :            : 
     201                 :            :         // attribute not found, keep searching base classes
     202                 :            : 
     203         [ +  + ]:      68946 :         if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
     204                 :            :             DEBUG_printf("mp_obj_class_lookup: No more parents\n");
     205                 :            :             return;
     206                 :            :         #if MICROPY_MULTIPLE_INHERITANCE
     207         [ +  + ]:      27277 :         } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
     208                 :       6542 :             const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
     209                 :       6542 :             const mp_obj_t *item = parent_tuple->items;
     210                 :       6542 :             const mp_obj_t *top = item + parent_tuple->len - 1;
     211         [ +  + ]:      12996 :             for (; item < top; ++item) {
     212   [ +  -  -  + ]:       6542 :                 assert(mp_obj_is_type(*item, &mp_type_type));
     213                 :       6542 :                 mp_obj_type_t *bt = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
     214         [ +  + ]:       6542 :                 if (bt == &mp_type_object) {
     215                 :            :                     // Not a "real" type
     216                 :          6 :                     continue;
     217                 :            :                 }
     218                 :       6536 :                 mp_obj_class_lookup(lookup, bt);
     219         [ +  + ]:       6536 :                 if (lookup->dest[0] != MP_OBJ_NULL) {
     220                 :            :                     return;
     221                 :            :                 }
     222                 :            :             }
     223                 :            : 
     224                 :            :             // search last base (simple tail recursion elimination)
     225   [ +  -  -  + ]:       6454 :             assert(mp_obj_is_type(*item, &mp_type_type));
     226                 :            :             type = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
     227                 :            :         #endif
     228                 :            :         } else {
     229                 :            :             type = MP_OBJ_TYPE_GET_SLOT(type, parent);
     230                 :            :         }
     231         [ +  + ]:      27189 :         if (type == &mp_type_object) {
     232                 :            :             // Not a "real" type
     233                 :            :             return;
     234                 :            :         }
     235                 :            :     }
     236                 :            : }
     237                 :            : 
     238                 :        237 : STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     239                 :        237 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     240         [ +  + ]:        237 :     qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
     241                 :        237 :     mp_obj_t member[2] = {MP_OBJ_NULL};
     242                 :        237 :     struct class_lookup_data lookup = {
     243                 :            :         .obj = self,
     244                 :            :         .attr = meth,
     245                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(print),
     246                 :            :         .dest = member,
     247                 :            :         .is_type = false,
     248                 :            :     };
     249                 :        237 :     mp_obj_class_lookup(&lookup, self->base.type);
     250   [ +  +  +  + ]:        237 :     if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {
     251                 :            :         // If there's no __str__, fall back to __repr__
     252                 :         48 :         lookup.attr = MP_QSTR___repr__;
     253                 :         48 :         lookup.slot_offset = 0;
     254                 :         48 :         mp_obj_class_lookup(&lookup, self->base.type);
     255                 :            :     }
     256                 :            : 
     257         [ +  + ]:        237 :     if (member[0] == MP_OBJ_SENTINEL) {
     258                 :            :         // Handle Exception subclasses specially
     259         [ +  + ]:         77 :         if (mp_obj_is_native_exception_instance(self->subobj[0])) {
     260         [ +  + ]:         37 :             if (kind != PRINT_STR) {
     261                 :         33 :                 mp_print_str(print, qstr_str(self->base.type->name));
     262                 :            :             }
     263                 :         37 :             mp_obj_print_helper(print, self->subobj[0], kind | PRINT_EXC_SUBCLASS);
     264                 :            :         } else {
     265                 :         40 :             mp_obj_print_helper(print, self->subobj[0], kind);
     266                 :            :         }
     267                 :        229 :         return;
     268                 :            :     }
     269                 :            : 
     270         [ +  + ]:        160 :     if (member[0] != MP_OBJ_NULL) {
     271                 :        152 :         mp_obj_t r = mp_call_function_1(member[0], self_in);
     272                 :        152 :         mp_obj_print_helper(print, r, PRINT_STR);
     273                 :        152 :         return;
     274                 :            :     }
     275                 :            : 
     276                 :            :     // TODO: CPython prints fully-qualified type name
     277                 :          8 :     mp_printf(print, "<%s object at %p>", mp_obj_get_type_str(self_in), self);
     278                 :            : }
     279                 :            : 
     280                 :       2323 : STATIC mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     281         [ -  + ]:       2323 :     assert(mp_obj_is_instance_type(self));
     282                 :            : 
     283                 :            :     // look for __new__ function
     284                 :       2323 :     mp_obj_t init_fn[2] = {MP_OBJ_NULL};
     285                 :       2323 :     struct class_lookup_data lookup = {
     286                 :            :         .obj = NULL,
     287                 :            :         .attr = MP_QSTR___new__,
     288                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(make_new),
     289                 :            :         .dest = init_fn,
     290                 :            :         .is_type = false,
     291                 :            :     };
     292                 :       2323 :     mp_obj_class_lookup(&lookup, self);
     293                 :            : 
     294                 :       2323 :     const mp_obj_type_t *native_base = NULL;
     295                 :       2323 :     mp_obj_instance_t *o;
     296         [ +  + ]:       2323 :     if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) {
     297                 :            :         // Either there is no __new__() method defined or there is a native
     298                 :            :         // constructor.  In both cases create a blank instance.
     299                 :       2299 :         o = mp_obj_new_instance(self, &native_base);
     300                 :            : 
     301                 :            :         // Since type->make_new() implements both __new__() and __init__() in
     302                 :            :         // one go, of which the latter may be overridden by the Python subclass,
     303                 :            :         // we defer (see the end of this function) the call of the native
     304                 :            :         // constructor to give a chance for the Python __init__() method to call
     305                 :            :         // said native constructor.
     306                 :            : 
     307                 :            :     } else {
     308                 :            :         // Call Python class __new__ function with all args to create an instance
     309                 :         24 :         mp_obj_t new_ret;
     310         [ +  + ]:         24 :         if (n_args == 0 && n_kw == 0) {
     311                 :         12 :             mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)};
     312                 :         12 :             new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2);
     313                 :            :         } else {
     314                 :         12 :             mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);
     315                 :         12 :             args2[0] = MP_OBJ_FROM_PTR(self);
     316                 :         12 :             memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
     317                 :         12 :             new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
     318                 :         12 :             m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
     319                 :            :         }
     320                 :            : 
     321                 :            :         // https://docs.python.org/3.4/reference/datamodel.html#object.__new__
     322                 :            :         // "If __new__() does not return an instance of cls, then the new
     323                 :            :         // instance's __init__() method will not be invoked."
     324         [ +  + ]:         24 :         if (mp_obj_get_type(new_ret) != self) {
     325                 :            :             return new_ret;
     326                 :            :         }
     327                 :            : 
     328                 :            :         // The instance returned by __new__() becomes the new object
     329                 :            :         o = MP_OBJ_TO_PTR(new_ret);
     330                 :            :     }
     331                 :            : 
     332                 :            :     // now call Python class __init__ function with all args
     333                 :            :     // This method has a chance to call super().__init__() to construct a
     334                 :            :     // possible native base class.
     335                 :       2303 :     init_fn[0] = init_fn[1] = MP_OBJ_NULL;
     336                 :       2303 :     lookup.obj = o;
     337                 :       2303 :     lookup.attr = MP_QSTR___init__;
     338                 :       2303 :     lookup.slot_offset = 0;
     339                 :       2303 :     mp_obj_class_lookup(&lookup, self);
     340         [ +  + ]:       2303 :     if (init_fn[0] != MP_OBJ_NULL) {
     341                 :       1045 :         mp_obj_t init_ret;
     342         [ +  + ]:       1045 :         if (n_args == 0 && n_kw == 0) {
     343                 :        279 :             init_ret = mp_call_method_n_kw(0, 0, init_fn);
     344                 :            :         } else {
     345                 :        766 :             mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw);
     346                 :        766 :             args2[0] = init_fn[0];
     347                 :        766 :             args2[1] = init_fn[1];
     348                 :        766 :             memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
     349                 :        766 :             init_ret = mp_call_method_n_kw(n_args, n_kw, args2);
     350                 :        766 :             m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
     351                 :            :         }
     352         [ +  + ]:       1045 :         if (init_ret != mp_const_none) {
     353                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
     354                 :            :             mp_raise_TypeError(MP_ERROR_TEXT("__init__() should return None"));
     355                 :            :             #else
     356                 :          4 :             mp_raise_msg_varg(&mp_type_TypeError,
     357                 :          4 :                 MP_ERROR_TEXT("__init__() should return None, not '%s'"), mp_obj_get_type_str(init_ret));
     358                 :            :             #endif
     359                 :            :         }
     360                 :            :     }
     361                 :            : 
     362                 :            :     // If the type had a native base that was not explicitly initialised
     363                 :            :     // (constructed) by the Python __init__() method then construct it now.
     364   [ +  +  +  + ]:       2299 :     if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) {
     365                 :        372 :         o->subobj[0] = MP_OBJ_TYPE_GET_SLOT(native_base, make_new)(native_base, n_args, n_kw, args);
     366                 :            :     }
     367                 :            : 
     368                 :            :     return MP_OBJ_FROM_PTR(o);
     369                 :            : }
     370                 :            : 
     371                 :            : // Qstrs for special methods are guaranteed to have a small value, so we use byte
     372                 :            : // type to represent them.
     373                 :            : const byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {
     374                 :            :     [MP_UNARY_OP_BOOL] = MP_QSTR___bool__,
     375                 :            :     [MP_UNARY_OP_LEN] = MP_QSTR___len__,
     376                 :            :     [MP_UNARY_OP_HASH] = MP_QSTR___hash__,
     377                 :            :     [MP_UNARY_OP_INT] = MP_QSTR___int__,
     378                 :            :     #if MICROPY_PY_ALL_SPECIAL_METHODS
     379                 :            :     [MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__,
     380                 :            :     [MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__,
     381                 :            :     [MP_UNARY_OP_INVERT] = MP_QSTR___invert__,
     382                 :            :     [MP_UNARY_OP_ABS] = MP_QSTR___abs__,
     383                 :            :     #endif
     384                 :            :     #if MICROPY_PY_BUILTINS_FLOAT
     385                 :            :     [MP_UNARY_OP_FLOAT_MAYBE] = MP_QSTR___float__,
     386                 :            :     #if MICROPY_PY_BUILTINS_COMPLEX
     387                 :            :     [MP_UNARY_OP_COMPLEX_MAYBE] = MP_QSTR___complex__,
     388                 :            :     #endif
     389                 :            :     #endif
     390                 :            :     #if MICROPY_PY_SYS_GETSIZEOF
     391                 :            :     [MP_UNARY_OP_SIZEOF] = MP_QSTR___sizeof__,
     392                 :            :     #endif
     393                 :            : };
     394                 :            : 
     395                 :        246 : STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
     396                 :        246 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     397                 :            : 
     398                 :            :     #if MICROPY_PY_SYS_GETSIZEOF
     399         [ +  + ]:        246 :     if (MP_UNLIKELY(op == MP_UNARY_OP_SIZEOF)) {
     400                 :            :         // TODO: This doesn't count inherited objects (self->subobj)
     401                 :          4 :         const mp_obj_type_t *native_base;
     402                 :          4 :         size_t num_native_bases = instance_count_native_bases(mp_obj_get_type(self_in), &native_base);
     403                 :            : 
     404                 :          4 :         size_t sz = sizeof(*self) + sizeof(*self->subobj) * num_native_bases
     405                 :          4 :             + sizeof(*self->members.table) * self->members.alloc;
     406                 :          4 :         return MP_OBJ_NEW_SMALL_INT(sz);
     407                 :            :     }
     408                 :            :     #endif
     409                 :            : 
     410                 :        242 :     qstr op_name = mp_unary_op_method_name[op];
     411                 :            :     /* Still try to lookup native slot
     412                 :            :     if (op_name == 0) {
     413                 :            :         return MP_OBJ_NULL;
     414                 :            :     }
     415                 :            :     */
     416                 :        242 :     mp_obj_t member[2] = {MP_OBJ_NULL};
     417                 :        242 :     struct class_lookup_data lookup = {
     418                 :            :         .obj = self,
     419                 :            :         .attr = op_name,
     420                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(unary_op),
     421                 :            :         .dest = member,
     422                 :            :         .is_type = false,
     423                 :            :     };
     424                 :        242 :     mp_obj_class_lookup(&lookup, self->base.type);
     425         [ +  + ]:        242 :     if (member[0] == MP_OBJ_SENTINEL) {
     426                 :         48 :         return mp_unary_op(op, self->subobj[0]);
     427         [ +  + ]:        194 :     } else if (member[0] != MP_OBJ_NULL) {
     428                 :        112 :         mp_obj_t val = mp_call_function_1(member[0], self_in);
     429                 :            : 
     430      [ +  +  + ]:        112 :         switch (op) {
     431                 :         20 :             case MP_UNARY_OP_HASH:
     432                 :            :                 // __hash__ must return a small int
     433                 :         20 :                 val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val));
     434                 :         16 :                 break;
     435                 :            :             case MP_UNARY_OP_INT:
     436                 :            :                 // Must return int
     437   [ +  +  -  +  :          8 :                 if (!mp_obj_is_int(val)) {
                   -  - ]
     438                 :          4 :                     mp_raise_TypeError(NULL);
     439                 :            :                 }
     440                 :            :                 break;
     441                 :        104 :             default:
     442                 :            :                 // No need to do anything
     443                 :        104 :                 ;
     444                 :            :         }
     445                 :        104 :         return val;
     446                 :            :     } else {
     447         [ +  + ]:         82 :         if (op == MP_UNARY_OP_HASH) {
     448                 :          8 :             lookup.attr = MP_QSTR___eq__;
     449                 :          8 :             mp_obj_class_lookup(&lookup, self->base.type);
     450         [ +  + ]:          8 :             if (member[0] == MP_OBJ_NULL) {
     451                 :            :                 // https://docs.python.org/3/reference/datamodel.html#object.__hash__
     452                 :            :                 // "User-defined classes have __eq__() and __hash__() methods by default;
     453                 :            :                 // with them, all objects compare unequal (except with themselves) and
     454                 :            :                 // x.__hash__() returns an appropriate value such that x == y implies
     455                 :            :                 // both that x is y and hash(x) == hash(y)."
     456                 :          4 :                 return MP_OBJ_NEW_SMALL_INT((mp_uint_t)self_in);
     457                 :            :             }
     458                 :            :             // "A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None.
     459                 :            :             // When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError"
     460                 :            :         }
     461                 :            : 
     462                 :         78 :         return MP_OBJ_NULL; // op not supported
     463                 :            :     }
     464                 :            : }
     465                 :            : 
     466                 :            : // Binary-op enum values not listed here will have the default value of 0 in the
     467                 :            : // table, corresponding to MP_QSTRnull, and are therefore unsupported (a lookup will
     468                 :            : // fail).  They can be added at the expense of code size for the qstr.
     469                 :            : // Qstrs for special methods are guaranteed to have a small value, so we use byte
     470                 :            : // type to represent them.
     471                 :            : const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
     472                 :            :     [MP_BINARY_OP_LESS] = MP_QSTR___lt__,
     473                 :            :     [MP_BINARY_OP_MORE] = MP_QSTR___gt__,
     474                 :            :     [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
     475                 :            :     [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
     476                 :            :     [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
     477                 :            :     [MP_BINARY_OP_NOT_EQUAL] = MP_QSTR___ne__,
     478                 :            :     [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__,
     479                 :            : 
     480                 :            :     // If an inplace method is not found a normal method will be used as a fallback
     481                 :            :     [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__,
     482                 :            :     [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,
     483                 :            :     #if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS
     484                 :            :     [MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__,
     485                 :            :     [MP_BINARY_OP_INPLACE_MAT_MULTIPLY] = MP_QSTR___imatmul__,
     486                 :            :     [MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__,
     487                 :            :     [MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__,
     488                 :            :     [MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__,
     489                 :            :     [MP_BINARY_OP_INPLACE_POWER] = MP_QSTR___ipow__,
     490                 :            :     [MP_BINARY_OP_INPLACE_OR] = MP_QSTR___ior__,
     491                 :            :     [MP_BINARY_OP_INPLACE_XOR] = MP_QSTR___ixor__,
     492                 :            :     [MP_BINARY_OP_INPLACE_AND] = MP_QSTR___iand__,
     493                 :            :     [MP_BINARY_OP_INPLACE_LSHIFT] = MP_QSTR___ilshift__,
     494                 :            :     [MP_BINARY_OP_INPLACE_RSHIFT] = MP_QSTR___irshift__,
     495                 :            :     #endif
     496                 :            : 
     497                 :            :     [MP_BINARY_OP_ADD] = MP_QSTR___add__,
     498                 :            :     [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
     499                 :            :     #if MICROPY_PY_ALL_SPECIAL_METHODS
     500                 :            :     [MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__,
     501                 :            :     [MP_BINARY_OP_MAT_MULTIPLY] = MP_QSTR___matmul__,
     502                 :            :     [MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__,
     503                 :            :     [MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__,
     504                 :            :     [MP_BINARY_OP_MODULO] = MP_QSTR___mod__,
     505                 :            :     [MP_BINARY_OP_DIVMOD] = MP_QSTR___divmod__,
     506                 :            :     [MP_BINARY_OP_POWER] = MP_QSTR___pow__,
     507                 :            :     [MP_BINARY_OP_OR] = MP_QSTR___or__,
     508                 :            :     [MP_BINARY_OP_XOR] = MP_QSTR___xor__,
     509                 :            :     [MP_BINARY_OP_AND] = MP_QSTR___and__,
     510                 :            :     [MP_BINARY_OP_LSHIFT] = MP_QSTR___lshift__,
     511                 :            :     [MP_BINARY_OP_RSHIFT] = MP_QSTR___rshift__,
     512                 :            :     #endif
     513                 :            : 
     514                 :            :     #if MICROPY_PY_REVERSE_SPECIAL_METHODS
     515                 :            :     [MP_BINARY_OP_REVERSE_ADD] = MP_QSTR___radd__,
     516                 :            :     [MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__,
     517                 :            :     #if MICROPY_PY_ALL_SPECIAL_METHODS
     518                 :            :     [MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__,
     519                 :            :     [MP_BINARY_OP_REVERSE_MAT_MULTIPLY] = MP_QSTR___rmatmul__,
     520                 :            :     [MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__,
     521                 :            :     [MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__,
     522                 :            :     [MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__,
     523                 :            :     [MP_BINARY_OP_REVERSE_POWER] = MP_QSTR___rpow__,
     524                 :            :     [MP_BINARY_OP_REVERSE_OR] = MP_QSTR___ror__,
     525                 :            :     [MP_BINARY_OP_REVERSE_XOR] = MP_QSTR___rxor__,
     526                 :            :     [MP_BINARY_OP_REVERSE_AND] = MP_QSTR___rand__,
     527                 :            :     [MP_BINARY_OP_REVERSE_LSHIFT] = MP_QSTR___rlshift__,
     528                 :            :     [MP_BINARY_OP_REVERSE_RSHIFT] = MP_QSTR___rrshift__,
     529                 :            :     #endif
     530                 :            :     #endif
     531                 :            : };
     532                 :            : 
     533                 :       1033 : STATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     534                 :            :     // Note: For ducktyping, CPython does not look in the instance members or use
     535                 :            :     // __getattr__ or __getattribute__.  It only looks in the class dictionary.
     536                 :       1033 :     mp_obj_instance_t *lhs = MP_OBJ_TO_PTR(lhs_in);
     537                 :       1037 : retry:;
     538                 :       1037 :     qstr op_name = mp_binary_op_method_name[op];
     539                 :            :     /* Still try to lookup native slot
     540                 :            :     if (op_name == 0) {
     541                 :            :         return MP_OBJ_NULL;
     542                 :            :     }
     543                 :            :     */
     544                 :       1037 :     mp_obj_t dest[3] = {MP_OBJ_NULL};
     545                 :       1037 :     struct class_lookup_data lookup = {
     546                 :            :         .obj = lhs,
     547                 :            :         .attr = op_name,
     548                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(binary_op),
     549                 :            :         .dest = dest,
     550                 :            :         .is_type = false,
     551                 :            :     };
     552                 :       1037 :     mp_obj_class_lookup(&lookup, lhs->base.type);
     553                 :            : 
     554                 :       1037 :     mp_obj_t res;
     555         [ +  + ]:       1037 :     if (dest[0] == MP_OBJ_SENTINEL) {
     556                 :        100 :         res = mp_binary_op(op, lhs->subobj[0], rhs_in);
     557         [ +  + ]:        937 :     } else if (dest[0] != MP_OBJ_NULL) {
     558                 :        733 :         dest[2] = rhs_in;
     559                 :        733 :         res = mp_call_method_n_kw(1, 0, dest);
     560   [ +  +  +  + ]:        733 :         res = op == MP_BINARY_OP_CONTAINS ? mp_obj_new_bool(mp_obj_is_true(res)) : res;
     561                 :            :     } else {
     562                 :            :         // If this was an inplace method, fallback to normal method
     563                 :            :         // https://docs.python.org/3/reference/datamodel.html#object.__iadd__ :
     564                 :            :         // "If a specific method is not defined, the augmented assignment
     565                 :            :         // falls back to the normal methods."
     566         [ +  + ]:        204 :         if (op >= MP_BINARY_OP_INPLACE_OR && op <= MP_BINARY_OP_INPLACE_POWER) {
     567                 :          4 :             op -= MP_BINARY_OP_INPLACE_OR - MP_BINARY_OP_OR;
     568                 :          4 :             goto retry;
     569                 :            :         }
     570                 :            :         return MP_OBJ_NULL; // op not supported
     571                 :            :     }
     572                 :            : 
     573                 :            :     #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED
     574                 :            :     // NotImplemented means "try other fallbacks (like calling __rop__
     575                 :            :     // instead of __op__) and if nothing works, raise TypeError". As
     576                 :            :     // MicroPython doesn't implement any fallbacks, signal to raise
     577                 :            :     // TypeError right away.
     578         [ +  + ]:        833 :     if (res == mp_const_notimplemented) {
     579                 :         12 :         return MP_OBJ_NULL; // op not supported
     580                 :            :     }
     581                 :            :     #endif
     582                 :            : 
     583                 :            :     return res;
     584                 :            : }
     585                 :            : 
     586                 :    2846152 : STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     587                 :            :     // logic: look in instance members then class locals
     588         [ -  + ]:    2846152 :     assert(mp_obj_is_instance_type(mp_obj_get_type(self_in)));
     589                 :    2846196 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     590                 :            : 
     591                 :            :     // Note: This is fast-path'ed in the VM for the MP_BC_LOAD_ATTR operation.
     592                 :    2846196 :     mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
     593         [ +  + ]:    2846196 :     if (elem != NULL) {
     594                 :            :         // object member, always treated as a value
     595                 :    1916417 :         dest[0] = elem->value;
     596                 :    2820546 :         return;
     597                 :            :     }
     598                 :            :     #if MICROPY_CPYTHON_COMPAT
     599         [ +  + ]:     929779 :     if (attr == MP_QSTR___dict__) {
     600                 :            :         // Create a new dict with a copy of the instance's map items.
     601                 :            :         // This creates, unlike CPython, a read-only __dict__ that can't be modified.
     602                 :         24 :         mp_obj_dict_t dict;
     603                 :         24 :         dict.base.type = &mp_type_dict;
     604                 :         24 :         dict.map = self->members;
     605                 :         24 :         dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(&dict));
     606                 :         24 :         mp_obj_dict_t *dest_dict = MP_OBJ_TO_PTR(dest[0]);
     607                 :         24 :         dest_dict->map.is_fixed = 1;
     608                 :         24 :         return;
     609                 :            :     }
     610                 :            :     #endif
     611                 :     929755 :     struct class_lookup_data lookup = {
     612                 :            :         .obj = self,
     613                 :            :         .attr = attr,
     614                 :            :         .slot_offset = 0,
     615                 :            :         .dest = dest,
     616                 :            :         .is_type = false,
     617                 :            :     };
     618                 :     929755 :     mp_obj_class_lookup(&lookup, self->base.type);
     619                 :     929753 :     mp_obj_t member = dest[0];
     620         [ +  + ]:     929753 :     if (member != MP_OBJ_NULL) {
     621         [ +  + ]:     904013 :         if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
     622                 :            :             // Class doesn't have any special accessors to check so return straightaway
     623                 :            :             return;
     624                 :            :         }
     625                 :            : 
     626                 :            :         #if MICROPY_PY_BUILTINS_PROPERTY
     627   [ -  +  -  +  :        140 :         if (mp_obj_is_type(member, &mp_type_property)) {
          -  +  -  +  +  
                -  +  + ]
     628                 :            :             // object member is a property; delegate the load to the property
     629                 :            :             // Note: This is an optimisation for code size and execution time.
     630                 :            :             // The proper way to do it is have the functionality just below
     631                 :            :             // in a __get__ method of the property object, and then it would
     632                 :            :             // be called by the descriptor code down below.  But that way
     633                 :            :             // requires overhead for the nested mp_call's and overhead for
     634                 :            :             // the code.
     635                 :         64 :             const mp_obj_t *proxy = mp_obj_property_get(member);
     636         [ +  + ]:         64 :             if (proxy[0] == mp_const_none) {
     637                 :          4 :                 mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT("unreadable attribute"));
     638                 :            :             } else {
     639                 :         60 :                 dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
     640                 :            :             }
     641                 :         60 :             return;
     642                 :            :         }
     643                 :            :         #endif
     644                 :            : 
     645                 :            :         #if MICROPY_PY_DESCRIPTORS
     646                 :            :         // found a class attribute; if it has a __get__ method then call it with the
     647                 :            :         // class instance and class as arguments and return the result
     648                 :            :         // Note that this is functionally correct but very slow: each load_attr
     649                 :            :         // requires an extra mp_load_method_maybe to check for the __get__.
     650                 :         76 :         mp_obj_t attr_get_method[4];
     651                 :         76 :         mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method);
     652         [ +  + ]:         76 :         if (attr_get_method[0] != MP_OBJ_NULL) {
     653                 :          4 :             attr_get_method[2] = self_in;
     654                 :          4 :             attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in));
     655                 :          4 :             dest[0] = mp_call_method_n_kw(2, 0, attr_get_method);
     656                 :            :         }
     657                 :            :         #endif
     658                 :         76 :         return;
     659                 :            :     }
     660                 :            : 
     661                 :            :     // try __getattr__
     662         [ +  + ]:      25740 :     if (attr != MP_QSTR___getattr__) {
     663                 :            :         #if MICROPY_PY_DELATTR_SETATTR
     664                 :            :         // If the requested attr is __setattr__/__delattr__ then don't delegate the lookup
     665                 :            :         // to __getattr__.  If we followed CPython's behaviour then __setattr__/__delattr__
     666                 :            :         // would have already been found in the "object" base class.
     667         [ +  + ]:      12922 :         if (attr == MP_QSTR___setattr__ || attr == MP_QSTR___delattr__) {
     668                 :         96 :             return;
     669                 :            :         }
     670                 :            :         #endif
     671                 :            : 
     672                 :      12870 :         mp_obj_t dest2[3];
     673                 :      12870 :         mp_load_method_maybe(self_in, MP_QSTR___getattr__, dest2);
     674         [ +  + ]:      12870 :         if (dest2[0] != MP_OBJ_NULL) {
     675                 :            :             // __getattr__ exists, call it and return its result
     676                 :         68 :             dest2[2] = MP_OBJ_NEW_QSTR(attr);
     677                 :         68 :             dest[0] = mp_call_method_n_kw(1, 0, dest2);
     678                 :         44 :             return;
     679                 :            :         }
     680                 :            :     }
     681                 :            : }
     682                 :            : 
     683                 :     314472 : STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
     684                 :     314472 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     685                 :            : 
     686         [ +  + ]:     314472 :     if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
     687                 :            :         // Class doesn't have any special accessors so skip their checks
     688                 :     314380 :         goto skip_special_accessors;
     689                 :            :     }
     690                 :            : 
     691                 :            :     #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS
     692                 :            :     // With property and/or descriptors enabled we need to do a lookup
     693                 :            :     // first in the class dict for the attribute to see if the store should
     694                 :            :     // be delegated.
     695                 :         92 :     mp_obj_t member[2] = {MP_OBJ_NULL};
     696                 :         92 :     struct class_lookup_data lookup = {
     697                 :            :         .obj = self,
     698                 :            :         .attr = attr,
     699                 :            :         .slot_offset = 0,
     700                 :            :         .dest = member,
     701                 :            :         .is_type = false,
     702                 :            :     };
     703                 :         92 :     mp_obj_class_lookup(&lookup, self->base.type);
     704                 :            : 
     705         [ +  + ]:         92 :     if (member[0] != MP_OBJ_NULL) {
     706                 :            :         #if MICROPY_PY_BUILTINS_PROPERTY
     707   [ -  +  -  +  :         44 :         if (mp_obj_is_type(member[0], &mp_type_property)) {
          -  +  -  +  +  
                -  +  + ]
     708                 :            :             // attribute exists and is a property; delegate the store/delete
     709                 :            :             // Note: This is an optimisation for code size and execution time.
     710                 :            :             // The proper way to do it is have the functionality just below in
     711                 :            :             // a __set__/__delete__ method of the property object, and then it
     712                 :            :             // would be called by the descriptor code down below.  But that way
     713                 :            :             // requires overhead for the nested mp_call's and overhead for
     714                 :            :             // the code.
     715                 :         28 :             const mp_obj_t *proxy = mp_obj_property_get(member[0]);
     716                 :         28 :             mp_obj_t dest[2] = {self_in, value};
     717         [ +  + ]:         28 :             if (value == MP_OBJ_NULL) {
     718                 :            :                 // delete attribute
     719         [ +  + ]:         12 :                 if (proxy[2] == mp_const_none) {
     720                 :            :                     // TODO better error message?
     721                 :            :                     return false;
     722                 :            :                 } else {
     723                 :          8 :                     mp_call_function_n_kw(proxy[2], 1, 0, dest);
     724                 :          8 :                     return true;
     725                 :            :                 }
     726                 :            :             } else {
     727                 :            :                 // store attribute
     728         [ +  + ]:         16 :                 if (proxy[1] == mp_const_none) {
     729                 :            :                     // TODO better error message?
     730                 :            :                     return false;
     731                 :            :                 } else {
     732                 :          8 :                     mp_call_function_n_kw(proxy[1], 2, 0, dest);
     733                 :          8 :                     return true;
     734                 :            :                 }
     735                 :            :             }
     736                 :            :         }
     737                 :            :         #endif
     738                 :            : 
     739                 :            :         #if MICROPY_PY_DESCRIPTORS
     740                 :            :         // found a class attribute; if it has a __set__/__delete__ method then
     741                 :            :         // call it with the class instance (and value) as arguments
     742         [ +  + ]:         16 :         if (value == MP_OBJ_NULL) {
     743                 :            :             // delete attribute
     744                 :          8 :             mp_obj_t attr_delete_method[3];
     745                 :          8 :             mp_load_method_maybe(member[0], MP_QSTR___delete__, attr_delete_method);
     746         [ +  + ]:          8 :             if (attr_delete_method[0] != MP_OBJ_NULL) {
     747                 :          4 :                 attr_delete_method[2] = self_in;
     748                 :          4 :                 mp_call_method_n_kw(1, 0, attr_delete_method);
     749                 :          4 :                 return true;
     750                 :            :             }
     751                 :            :         } else {
     752                 :            :             // store attribute
     753                 :          8 :             mp_obj_t attr_set_method[4];
     754                 :          8 :             mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method);
     755         [ +  + ]:          8 :             if (attr_set_method[0] != MP_OBJ_NULL) {
     756                 :          4 :                 attr_set_method[2] = self_in;
     757                 :          4 :                 attr_set_method[3] = value;
     758                 :          4 :                 mp_call_method_n_kw(2, 0, attr_set_method);
     759                 :          4 :                 return true;
     760                 :            :             }
     761                 :            :         }
     762                 :            :         #endif
     763                 :            :     }
     764                 :            :     #endif
     765                 :            : 
     766                 :            :     #if MICROPY_PY_DELATTR_SETATTR
     767         [ +  + ]:         56 :     if (value == MP_OBJ_NULL) {
     768                 :            :         // delete attribute
     769                 :            :         // try __delattr__ first
     770                 :         20 :         mp_obj_t attr_delattr_method[3];
     771                 :         20 :         mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method);
     772         [ +  - ]:         20 :         if (attr_delattr_method[0] != MP_OBJ_NULL) {
     773                 :            :             // __delattr__ exists, so call it
     774                 :         20 :             attr_delattr_method[2] = MP_OBJ_NEW_QSTR(attr);
     775                 :         20 :             mp_call_method_n_kw(1, 0, attr_delattr_method);
     776                 :         20 :             return true;
     777                 :            :         }
     778                 :            :     } else {
     779                 :            :         // store attribute
     780                 :            :         // try __setattr__ first
     781                 :         36 :         mp_obj_t attr_setattr_method[4];
     782                 :         36 :         mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method);
     783         [ +  + ]:         36 :         if (attr_setattr_method[0] != MP_OBJ_NULL) {
     784                 :            :             // __setattr__ exists, so call it
     785                 :         16 :             attr_setattr_method[2] = MP_OBJ_NEW_QSTR(attr);
     786                 :         16 :             attr_setattr_method[3] = value;
     787                 :         16 :             mp_call_method_n_kw(2, 0, attr_setattr_method);
     788                 :         16 :             return true;
     789                 :            :         }
     790                 :            :     }
     791                 :            :     #endif
     792                 :            : 
     793                 :     314400 : skip_special_accessors:
     794                 :            : 
     795         [ +  + ]:     314400 :     if (value == MP_OBJ_NULL) {
     796                 :            :         // delete attribute
     797                 :         16 :         mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
     798                 :         16 :         return elem != NULL;
     799                 :            :     } else {
     800                 :            :         // store attribute
     801                 :     314384 :         mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
     802                 :     314384 :         return true;
     803                 :            :     }
     804                 :            : }
     805                 :            : 
     806                 :    3160614 : STATIC void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     807         [ +  + ]:    3160614 :     if (dest[0] == MP_OBJ_NULL) {
     808                 :    2846196 :         mp_obj_instance_load_attr(self_in, attr, dest);
     809                 :            :     } else {
     810         [ +  + ]:     314418 :         if (mp_obj_instance_store_attr(self_in, attr, dest[1])) {
     811                 :     314452 :             dest[0] = MP_OBJ_NULL; // indicate success
     812                 :            :         }
     813                 :            :     }
     814                 :    3160637 : }
     815                 :            : 
     816                 :        144 : STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
     817                 :        144 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     818                 :        144 :     mp_obj_t member[4] = {MP_OBJ_NULL, MP_OBJ_NULL, index, value};
     819                 :        144 :     struct class_lookup_data lookup = {
     820                 :            :         .obj = self,
     821                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(subscr),
     822                 :            :         .dest = member,
     823                 :            :         .is_type = false,
     824                 :            :     };
     825         [ +  + ]:        144 :     if (value == MP_OBJ_NULL) {
     826                 :            :         // delete item
     827                 :          8 :         lookup.attr = MP_QSTR___delitem__;
     828         [ +  + ]:        136 :     } else if (value == MP_OBJ_SENTINEL) {
     829                 :            :         // load item
     830                 :        124 :         lookup.attr = MP_QSTR___getitem__;
     831                 :            :     } else {
     832                 :            :         // store item
     833                 :         12 :         lookup.attr = MP_QSTR___setitem__;
     834                 :            :     }
     835                 :        144 :     mp_obj_class_lookup(&lookup, self->base.type);
     836         [ +  + ]:        144 :     if (member[0] == MP_OBJ_SENTINEL) {
     837                 :         16 :         return mp_obj_subscr(self->subobj[0], index, value);
     838         [ +  + ]:        128 :     } else if (member[0] != MP_OBJ_NULL) {
     839         [ +  + ]:        124 :         size_t n_args = value == MP_OBJ_NULL || value == MP_OBJ_SENTINEL ? 1 : 2;
     840                 :        124 :         mp_obj_t ret = mp_call_method_n_kw(n_args, 0, member);
     841         [ +  + ]:        124 :         if (value == MP_OBJ_SENTINEL) {
     842                 :            :             return ret;
     843                 :            :         } else {
     844                 :         16 :             return mp_const_none;
     845                 :            :         }
     846                 :            :     } else {
     847                 :            :         return MP_OBJ_NULL; // op not supported
     848                 :            :     }
     849                 :            : }
     850                 :            : 
     851                 :         48 : STATIC mp_obj_t mp_obj_instance_get_call(mp_obj_t self_in, mp_obj_t *member) {
     852                 :         48 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     853                 :         48 :     struct class_lookup_data lookup = {
     854                 :            :         .obj = self,
     855                 :            :         .attr = MP_QSTR___call__,
     856                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(call),
     857                 :            :         .dest = member,
     858                 :            :         .is_type = false,
     859                 :            :     };
     860                 :         48 :     mp_obj_class_lookup(&lookup, self->base.type);
     861                 :         48 :     return member[0];
     862                 :            : }
     863                 :            : 
     864                 :         12 : bool mp_obj_instance_is_callable(mp_obj_t self_in) {
     865                 :         12 :     mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
     866                 :         12 :     return mp_obj_instance_get_call(self_in, member) != MP_OBJ_NULL;
     867                 :            : }
     868                 :            : 
     869                 :         36 : mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     870                 :         36 :     mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
     871                 :         36 :     mp_obj_t call = mp_obj_instance_get_call(self_in, member);
     872         [ +  + ]:         36 :     if (call == MP_OBJ_NULL) {
     873                 :            :         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
     874                 :            :         mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
     875                 :            :         #else
     876                 :          4 :         mp_raise_msg_varg(&mp_type_TypeError,
     877                 :          4 :             MP_ERROR_TEXT("'%s' object isn't callable"), mp_obj_get_type_str(self_in));
     878                 :            :         #endif
     879                 :            :     }
     880                 :         32 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     881         [ +  + ]:         32 :     if (call == MP_OBJ_SENTINEL) {
     882                 :          4 :         return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
     883                 :            :     }
     884                 :            : 
     885                 :         28 :     return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args);
     886                 :            : }
     887                 :            : 
     888                 :            : // Note that iter_buf may be NULL, and needs to be allocated if needed
     889                 :     143405 : mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
     890                 :     143405 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     891                 :     143405 :     mp_obj_t member[2] = {MP_OBJ_NULL};
     892                 :     143405 :     struct class_lookup_data lookup = {
     893                 :            :         .obj = self,
     894                 :            :         .attr = MP_QSTR___iter__,
     895                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(iter),
     896                 :            :         .dest = member,
     897                 :            :         .is_type = false,
     898                 :            :     };
     899                 :     143405 :     mp_obj_class_lookup(&lookup, self->base.type);
     900         [ +  + ]:     143405 :     if (member[0] == MP_OBJ_NULL) {
     901                 :            :         return MP_OBJ_NULL;
     902         [ +  + ]:     143377 :     } else if (member[0] == MP_OBJ_SENTINEL) {
     903                 :         16 :         const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
     904         [ +  + ]:         16 :         if (type->flags & MP_TYPE_FLAG_ITER_IS_ITERNEXT) {
     905                 :          8 :             return self->subobj[0];
     906                 :            :         } else {
     907         [ +  + ]:          8 :             if (iter_buf == NULL) {
     908                 :          4 :                 iter_buf = m_new_obj(mp_obj_iter_buf_t);
     909                 :            :             }
     910                 :          8 :             return ((mp_getiter_fun_t)MP_OBJ_TYPE_GET_SLOT(type, iter))(self->subobj[0], iter_buf);
     911                 :            :         }
     912                 :            :     } else {
     913                 :     143361 :         return mp_call_method_n_kw(0, 0, member);
     914                 :            :     }
     915                 :            : }
     916                 :            : 
     917                 :         38 : STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
     918                 :         38 :     mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
     919                 :         38 :     mp_obj_t member[2] = {MP_OBJ_NULL};
     920                 :         38 :     struct class_lookup_data lookup = {
     921                 :            :         .obj = self,
     922                 :            :         .attr = MP_QSTR_, // don't actually look for a method
     923                 :            :         .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(buffer),
     924                 :            :         .dest = member,
     925                 :            :         .is_type = false,
     926                 :            :     };
     927                 :         38 :     mp_obj_class_lookup(&lookup, self->base.type);
     928         [ +  + ]:         38 :     if (member[0] == MP_OBJ_SENTINEL) {
     929                 :         18 :         const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
     930                 :         18 :         return MP_OBJ_TYPE_GET_SLOT(type, buffer)(self->subobj[0], bufinfo, flags);
     931                 :            :     } else {
     932                 :            :         return 1; // object does not support buffer protocol
     933                 :            :     }
     934                 :            : }
     935                 :            : 
     936                 :            : /******************************************************************************/
     937                 :            : // type object
     938                 :            : //  - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
     939                 :            : //  - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object
     940                 :            : //  - creating a new class (a new type) creates a new mp_obj_type_t
     941                 :            : 
     942                 :            : #if ENABLE_SPECIAL_ACCESSORS
     943                 :       6138 : STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
     944                 :            :     #if MICROPY_PY_DELATTR_SETATTR
     945         [ +  + ]:       6138 :     if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) {
     946                 :            :         return true;
     947                 :            :     }
     948                 :            :     #endif
     949                 :            :     #if MICROPY_PY_BUILTINS_PROPERTY
     950   [ -  +  -  +  :       6122 :     if (mp_obj_is_type(value, &mp_type_property)) {
          -  +  -  +  +  
                +  +  + ]
     951                 :            :         return true;
     952                 :            :     }
     953                 :            :     #endif
     954                 :            :     #if MICROPY_PY_DESCRIPTORS
     955                 :            :     static const uint8_t to_check[] = {
     956                 :            :         MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__,
     957                 :            :     };
     958         [ +  + ]:      24340 :     for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) {
     959                 :      18256 :         mp_obj_t dest_temp[2];
     960                 :      18256 :         mp_load_method_protected(value, to_check[i], dest_temp, true);
     961         [ +  + ]:      18256 :         if (dest_temp[0] != MP_OBJ_NULL) {
     962                 :          4 :             return true;
     963                 :            :         }
     964                 :            :     }
     965                 :            :     #endif
     966                 :            :     return false;
     967                 :            : }
     968                 :            : #endif
     969                 :            : 
     970                 :        410 : STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     971                 :        410 :     (void)kind;
     972                 :        410 :     mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
     973                 :        410 :     mp_printf(print, "<class '%q'>", self->name);
     974                 :        410 : }
     975                 :            : 
     976                 :       6421 : STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     977                 :       6421 :     (void)type_in;
     978                 :            : 
     979                 :       6421 :     mp_arg_check_num(n_args, n_kw, 1, 3, false);
     980                 :            : 
     981      [ +  +  + ]:       6417 :     switch (n_args) {
     982                 :       4903 :         case 1:
     983                 :       4903 :             return MP_OBJ_FROM_PTR(mp_obj_get_type(args[0]));
     984                 :            : 
     985                 :       1510 :         case 3:
     986                 :            :             // args[0] = name
     987                 :            :             // args[1] = bases tuple
     988                 :            :             // args[2] = locals dict
     989                 :       1510 :             return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]);
     990                 :            : 
     991                 :            :         default:
     992                 :          4 :             mp_raise_TypeError(MP_ERROR_TEXT("type takes 1 or 3 arguments"));
     993                 :            :     }
     994                 :            : }
     995                 :            : 
     996                 :     255168 : STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     997                 :            :     // instantiate an instance of a class
     998                 :            : 
     999                 :     255168 :     mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
    1000                 :            : 
    1001         [ +  + ]:     255168 :     if (!MP_OBJ_TYPE_HAS_SLOT(self, make_new)) {
    1002                 :            :         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1003                 :            :         mp_raise_TypeError(MP_ERROR_TEXT("can't create instance"));
    1004                 :            :         #else
    1005                 :          2 :         mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("can't create '%q' instances"), self->name);
    1006                 :            :         #endif
    1007                 :            :     }
    1008                 :            : 
    1009                 :            :     // make new instance
    1010                 :     255166 :     mp_obj_t o = MP_OBJ_TYPE_GET_SLOT(self, make_new)(self, n_args, n_kw, args);
    1011                 :            : 
    1012                 :            :     // return new instance
    1013                 :     254744 :     return o;
    1014                 :            : }
    1015                 :            : 
    1016                 :       7209 : STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
    1017   [ +  -  -  + ]:       7209 :     assert(mp_obj_is_type(self_in, &mp_type_type));
    1018                 :       7209 :     mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
    1019                 :            : 
    1020         [ +  + ]:       7209 :     if (dest[0] == MP_OBJ_NULL) {
    1021                 :            :         // load attribute
    1022                 :            :         #if MICROPY_CPYTHON_COMPAT
    1023         [ +  + ]:       7145 :         if (attr == MP_QSTR___name__) {
    1024                 :         44 :             dest[0] = MP_OBJ_NEW_QSTR(self->name);
    1025                 :        160 :             return;
    1026                 :            :         }
    1027                 :            :         #if MICROPY_CPYTHON_COMPAT
    1028         [ +  + ]:       7101 :         if (attr == MP_QSTR___dict__) {
    1029                 :            :             // Returns a read-only dict of the class attributes.
    1030                 :            :             // If the internal locals is not fixed, a copy will be created.
    1031         [ +  + ]:         32 :             const mp_obj_dict_t *dict = MP_OBJ_TYPE_GET_SLOT_OR_NULL(self, locals_dict);
    1032         [ -  + ]:         28 :             if (!dict) {
    1033                 :          4 :                 dict = &mp_const_empty_dict_obj;
    1034                 :            :             }
    1035         [ +  + ]:         32 :             if (dict->map.is_fixed) {
    1036                 :         20 :                 dest[0] = MP_OBJ_FROM_PTR(dict);
    1037                 :            :             } else {
    1038                 :         12 :                 dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(dict));
    1039                 :         12 :                 mp_obj_dict_t *dict_copy = MP_OBJ_TO_PTR(dest[0]);
    1040                 :         12 :                 dict_copy->map.is_fixed = 1;
    1041                 :            :             }
    1042                 :         32 :             return;
    1043                 :            :         }
    1044                 :            :         #endif
    1045         [ +  + ]:       7069 :         if (attr == MP_QSTR___bases__) {
    1046         [ +  + ]:         84 :             if (self == &mp_type_object) {
    1047                 :          8 :                 dest[0] = mp_const_empty_tuple;
    1048                 :          8 :                 return;
    1049                 :            :             }
    1050         [ +  + ]:         76 :             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);
    1051                 :            :             #if MICROPY_MULTIPLE_INHERITANCE
    1052   [ -  +  -  +  :         76 :             if (mp_obj_is_type(parent_obj, &mp_type_tuple)) {
          -  +  -  +  +  
                -  +  + ]
    1053                 :         20 :                 dest[0] = parent_obj;
    1054                 :         20 :                 return;
    1055                 :            :             }
    1056                 :            :             #endif
    1057                 :         56 :             dest[0] = mp_obj_new_tuple(1, &parent_obj);
    1058                 :         56 :             return;
    1059                 :            :         }
    1060                 :            :         #endif
    1061                 :       6985 :         struct class_lookup_data lookup = {
    1062                 :            :             .obj = (mp_obj_instance_t *)self,
    1063                 :            :             .attr = attr,
    1064                 :            :             .slot_offset = 0,
    1065                 :            :             .dest = dest,
    1066                 :            :             .is_type = true,
    1067                 :            :         };
    1068                 :       6985 :         mp_obj_class_lookup(&lookup, self);
    1069                 :            :     } else {
    1070                 :            :         // delete/store attribute
    1071                 :            : 
    1072         [ +  - ]:         64 :         if (MP_OBJ_TYPE_HAS_SLOT(self, locals_dict)) {
    1073         [ -  + ]:         64 :             assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, locals_dict)))); // MicroPython restriction, for now
    1074                 :         64 :             mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(self, locals_dict)->map;
    1075         [ +  + ]:         64 :             if (locals_map->is_fixed) {
    1076                 :            :                 // can't apply delete/store to a fixed map
    1077                 :            :                 return;
    1078                 :            :             }
    1079         [ +  + ]:         56 :             if (dest[1] == MP_OBJ_NULL) {
    1080                 :            :                 // delete attribute
    1081                 :          8 :                 mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
    1082         [ +  + ]:          8 :                 if (elem != NULL) {
    1083                 :          4 :                     dest[0] = MP_OBJ_NULL; // indicate success
    1084                 :            :                 }
    1085                 :            :             } else {
    1086                 :            :                 #if ENABLE_SPECIAL_ACCESSORS
    1087                 :            :                 // Check if we add any special accessor methods with this store
    1088         [ +  + ]:         48 :                 if (!(self->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
    1089         [ +  + ]:         40 :                     if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) {
    1090         [ +  + ]:         10 :                         if (self->flags & MP_TYPE_FLAG_IS_SUBCLASSED) {
    1091                 :            :                             // This class is already subclassed so can't have special accessors added
    1092                 :          2 :                             mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT("can't add special method to already-subclassed class"));
    1093                 :            :                         }
    1094                 :          8 :                         self->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
    1095                 :            :                     }
    1096                 :            :                 }
    1097                 :            :                 #endif
    1098                 :            : 
    1099                 :            :                 // store attribute
    1100                 :         46 :                 mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
    1101                 :         46 :                 elem->value = dest[1];
    1102                 :         46 :                 dest[0] = MP_OBJ_NULL; // indicate success
    1103                 :            :             }
    1104                 :            :         }
    1105                 :            :     }
    1106                 :            : }
    1107                 :            : 
    1108                 :            : MP_DEFINE_CONST_OBJ_TYPE(
    1109                 :            :     mp_type_type,
    1110                 :            :     MP_QSTR_type,
    1111                 :            :     MP_TYPE_FLAG_NONE,
    1112                 :            :     make_new, type_make_new,
    1113                 :            :     print, type_print,
    1114                 :            :     call, type_call,
    1115                 :            :     unary_op, mp_generic_unary_op,
    1116                 :            :     attr, type_attr
    1117                 :            :     );
    1118                 :            : 
    1119                 :       1504 : mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
    1120                 :            :     // Verify input objects have expected type
    1121   [ -  +  -  +  :       1504 :     if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) {
          -  +  -  +  +  
                +  -  + ]
    1122                 :          4 :         mp_raise_TypeError(NULL);
    1123                 :            :     }
    1124         [ +  + ]:       1500 :     if (!mp_obj_is_dict_or_ordereddict(locals_dict)) {
    1125                 :          4 :         mp_raise_TypeError(NULL);
    1126                 :            :     }
    1127                 :            : 
    1128                 :            :     // TODO might need to make a copy of locals_dict; at least that's how CPython does it
    1129                 :            : 
    1130                 :            :     // Basic validation of base classes
    1131                 :       1496 :     uint16_t base_flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE
    1132                 :            :         | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE
    1133                 :            :         | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST
    1134                 :            :         | MP_TYPE_FLAG_ITER_IS_GETITER
    1135                 :            :         | MP_TYPE_FLAG_INSTANCE_TYPE;
    1136                 :       1496 :     size_t bases_len;
    1137                 :       1496 :     mp_obj_t *bases_items;
    1138                 :       1496 :     mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items);
    1139         [ +  + ]:       1979 :     for (size_t i = 0; i < bases_len; i++) {
    1140   [ +  +  -  + ]:        491 :         if (!mp_obj_is_type(bases_items[i], &mp_type_type)) {
    1141                 :          4 :             mp_raise_TypeError(NULL);
    1142                 :            :         }
    1143                 :        487 :         mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);
    1144                 :            :         // TODO: Verify with CPy, tested on function type
    1145         [ +  + ]:        487 :         if (!MP_OBJ_TYPE_HAS_SLOT(t, make_new)) {
    1146                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1147                 :            :             mp_raise_TypeError(MP_ERROR_TEXT("type isn't an acceptable base type"));
    1148                 :            :             #else
    1149                 :          4 :             mp_raise_msg_varg(&mp_type_TypeError,
    1150                 :          4 :                 MP_ERROR_TEXT("type '%q' isn't an acceptable base type"), t->name);
    1151                 :            :             #endif
    1152                 :            :         }
    1153                 :            :         #if ENABLE_SPECIAL_ACCESSORS
    1154         [ +  + ]:        483 :         if (mp_obj_is_instance_type(t)) {
    1155                 :        144 :             t->flags |= MP_TYPE_FLAG_IS_SUBCLASSED;
    1156                 :        144 :             base_flags |= t->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
    1157                 :            :         }
    1158                 :            :         #endif
    1159                 :            :     }
    1160                 :            : 
    1161                 :       1488 :     const void *base_protocol = NULL;
    1162         [ +  + ]:       1488 :     if (bases_len > 0) {
    1163         [ +  + ]:        425 :         base_protocol = MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_type_t *)MP_OBJ_TO_PTR(bases_items[0])), protocol);
    1164                 :            :     }
    1165                 :            : 
    1166                 :            :     // Allocate a variable-sized mp_obj_type_t with as many slots as we need
    1167                 :            :     // (currently 10, plus 1 for base, plus 1 for base-protocol).
    1168                 :            :     // Note: mp_obj_type_t is (2 + 3 + #slots) words, so going from 11 to 12 slots
    1169                 :            :     // moves from 4 to 5 gc blocks.
    1170         [ +  + ]:       2551 :     mp_obj_type_t *o = m_new_obj_var0(mp_obj_type_t, void *, 10 + (bases_len ? 1 : 0) + (base_protocol ? 1 : 0));
    1171                 :       1488 :     o->base.type = &mp_type_type;
    1172                 :       1488 :     o->flags = base_flags;
    1173                 :       1488 :     o->name = name;
    1174                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, make_new, mp_obj_instance_make_new, 0);
    1175                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, print, instance_print, 1);
    1176                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, call, mp_obj_instance_call, 2);
    1177                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, unary_op, instance_unary_op, 3);
    1178                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, binary_op, instance_binary_op, 4);
    1179                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, attr, mp_obj_instance_attr, 5);
    1180                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, subscr, instance_subscr, 6);
    1181                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, iter, mp_obj_instance_getiter, 7);
    1182                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, buffer, instance_get_buffer, 8);
    1183                 :            : 
    1184                 :       1488 :     mp_obj_dict_t *locals_ptr = MP_OBJ_TO_PTR(locals_dict);
    1185                 :       1488 :     MP_OBJ_TYPE_SET_SLOT(o, locals_dict, locals_ptr, 9);
    1186                 :            : 
    1187         [ +  + ]:       1488 :     if (bases_len > 0) {
    1188         [ +  + ]:        425 :         if (bases_len >= 2) {
    1189                 :            :             #if MICROPY_MULTIPLE_INHERITANCE
    1190                 :         58 :             MP_OBJ_TYPE_SET_SLOT(o, parent, MP_OBJ_TO_PTR(bases_tuple), 10);
    1191                 :            :             #else
    1192                 :            :             mp_raise_NotImplementedError(MP_ERROR_TEXT("multiple inheritance not supported"));
    1193                 :            :             #endif
    1194                 :            :         } else {
    1195                 :        367 :             MP_OBJ_TYPE_SET_SLOT(o, parent, MP_OBJ_TO_PTR(bases_items[0]), 10);
    1196                 :            :         }
    1197                 :            : 
    1198                 :            :         // Inherit protocol from a base class. This allows to define an
    1199                 :            :         // abstract base class which would translate C-level protocol to
    1200                 :            :         // Python method calls, and any subclass inheriting from it will
    1201                 :            :         // support this feature.
    1202         [ +  + ]:        425 :         if (base_protocol) {
    1203                 :         53 :             MP_OBJ_TYPE_SET_SLOT(o, protocol, base_protocol, 11);
    1204                 :            :         }
    1205                 :            :     }
    1206                 :            : 
    1207                 :            :     #if ENABLE_SPECIAL_ACCESSORS
    1208                 :            :     // Check if the class has any special accessor methods
    1209         [ +  + ]:       1488 :     if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
    1210         [ +  + ]:       8334 :         for (size_t i = 0; i < locals_ptr->map.alloc; i++) {
    1211         [ +  + ]:       6906 :             if (mp_map_slot_is_filled(&locals_ptr->map, i)) {
    1212                 :       6098 :                 const mp_map_elem_t *elem = &locals_ptr->map.table[i];
    1213         [ +  + ]:       6098 :                 if (check_for_special_accessors(elem->key, elem->value)) {
    1214                 :         44 :                     o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
    1215                 :         44 :                     break;
    1216                 :            :                 }
    1217                 :            :             }
    1218                 :            :         }
    1219                 :            :     }
    1220                 :            :     #endif
    1221                 :            : 
    1222                 :       1488 :     const mp_obj_type_t *native_base;
    1223                 :       1488 :     size_t num_native_bases = instance_count_native_bases(o, &native_base);
    1224         [ +  + ]:       1488 :     if (num_native_bases > 1) {
    1225                 :          4 :         mp_raise_TypeError(MP_ERROR_TEXT("multiple bases have instance lay-out conflict"));
    1226                 :            :     }
    1227                 :            : 
    1228                 :       1484 :     mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(o, locals_dict)->map;
    1229                 :       1484 :     mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
    1230         [ +  + ]:       1484 :     if (elem != NULL) {
    1231                 :            :         // __new__ slot exists; check if it is a function
    1232   [ +  -  +  - ]:         24 :         if (mp_obj_is_fun(elem->value)) {
    1233                 :            :             // __new__ is a function, wrap it in a staticmethod decorator
    1234                 :         24 :             elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value);
    1235                 :            :         }
    1236                 :            :     }
    1237                 :            : 
    1238                 :       1484 :     return MP_OBJ_FROM_PTR(o);
    1239                 :            : }
    1240                 :            : 
    1241                 :            : /******************************************************************************/
    1242                 :            : // super object
    1243                 :            : 
    1244                 :            : typedef struct _mp_obj_super_t {
    1245                 :            :     mp_obj_base_t base;
    1246                 :            :     mp_obj_t type;
    1247                 :            :     mp_obj_t obj;
    1248                 :            : } mp_obj_super_t;
    1249                 :            : 
    1250                 :          4 : STATIC void super_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
    1251                 :          4 :     (void)kind;
    1252                 :          4 :     mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in);
    1253                 :          4 :     mp_print_str(print, "<super: ");
    1254                 :          4 :     mp_obj_print_helper(print, self->type, PRINT_STR);
    1255                 :          4 :     mp_print_str(print, ", ");
    1256                 :          4 :     mp_obj_print_helper(print, self->obj, PRINT_STR);
    1257                 :          4 :     mp_print_str(print, ">");
    1258                 :          4 : }
    1259                 :            : 
    1260                 :         44 : STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    1261                 :         44 :     (void)type_in;
    1262                 :            :     // 0 arguments are turned into 2 in the compiler
    1263                 :            :     // 1 argument is not yet implemented
    1264                 :         44 :     mp_arg_check_num(n_args, n_kw, 2, 2, false);
    1265   [ +  +  -  + ]:         44 :     if (!mp_obj_is_type(args[0], &mp_type_type)) {
    1266                 :          4 :         mp_raise_TypeError(NULL);
    1267                 :            :     }
    1268                 :         40 :     mp_obj_super_t *o = m_new_obj(mp_obj_super_t);
    1269                 :         40 :     *o = (mp_obj_super_t) {{type_in}, args[0], args[1]};
    1270                 :         40 :     return MP_OBJ_FROM_PTR(o);
    1271                 :            : }
    1272                 :            : 
    1273                 :         94 : STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
    1274         [ +  + ]:         94 :     if (dest[0] != MP_OBJ_NULL) {
    1275                 :            :         // not load attribute
    1276                 :         46 :         return;
    1277                 :            :     }
    1278                 :            : 
    1279   [ +  -  -  + ]:         86 :     assert(mp_obj_is_type(self_in, &mp_type_super));
    1280                 :         86 :     mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in);
    1281                 :            : 
    1282   [ +  -  -  + ]:         86 :     assert(mp_obj_is_type(self->type, &mp_type_type));
    1283                 :            : 
    1284                 :         86 :     mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type);
    1285                 :            : 
    1286                 :         86 :     struct class_lookup_data lookup = {
    1287                 :         86 :         .obj = MP_OBJ_TO_PTR(self->obj),
    1288                 :            :         .attr = attr,
    1289                 :            :         .slot_offset = 0,
    1290                 :            :         .dest = dest,
    1291                 :            :         .is_type = false,
    1292                 :            :     };
    1293                 :            : 
    1294                 :            :     // Allow a call super().__init__() to reach any native base classes.
    1295         [ +  + ]:         86 :     if (attr == MP_QSTR___init__) {
    1296                 :         38 :         lookup.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(make_new);
    1297                 :            :     }
    1298                 :            : 
    1299         [ +  + ]:         86 :     if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
    1300                 :            :         // no parents, do nothing
    1301                 :            :     #if MICROPY_MULTIPLE_INHERITANCE
    1302         [ +  + ]:         58 :     } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
    1303                 :         16 :         const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
    1304                 :         16 :         size_t len = parent_tuple->len;
    1305                 :         16 :         const mp_obj_t *items = parent_tuple->items;
    1306         [ +  + ]:         40 :         for (size_t i = 0; i < len; i++) {
    1307   [ +  -  -  + ]:         28 :             assert(mp_obj_is_type(items[i], &mp_type_type));
    1308         [ +  + ]:         28 :             if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) {
    1309                 :            :                 // The "object" type will be searched at the end of this function,
    1310                 :            :                 // and we don't want to lookup native methods in object.
    1311                 :         12 :                 continue;
    1312                 :            :             }
    1313                 :            : 
    1314                 :         16 :             mp_obj_class_lookup(&lookup, (mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]));
    1315         [ +  + ]:         16 :             if (dest[0] != MP_OBJ_NULL) {
    1316                 :            :                 break;
    1317                 :            :             }
    1318                 :            :         }
    1319                 :            :     #endif
    1320         [ +  + ]:         42 :     } else if (MP_OBJ_TYPE_GET_SLOT(type, parent) != &mp_type_object) {
    1321                 :         34 :         mp_obj_class_lookup(&lookup, MP_OBJ_TYPE_GET_SLOT(type, parent));
    1322                 :            :     }
    1323                 :            : 
    1324         [ +  + ]:         86 :     if (dest[0] != MP_OBJ_NULL) {
    1325         [ +  + ]:         38 :         if (dest[0] == MP_OBJ_SENTINEL) {
    1326                 :            :             // Looked up native __init__ so defer to it
    1327                 :         10 :             dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
    1328                 :         10 :             dest[1] = self->obj;
    1329                 :            :         }
    1330                 :         38 :         return;
    1331                 :            :     }
    1332                 :            : 
    1333                 :            :     // Reset slot_offset so we don't look up any native methods in object,
    1334                 :            :     // because object never takes up the native base-class slot.
    1335                 :         48 :     lookup.slot_offset = 0;
    1336                 :            : 
    1337                 :         48 :     mp_obj_class_lookup(&lookup, &mp_type_object);
    1338                 :            : }
    1339                 :            : 
    1340                 :            : MP_DEFINE_CONST_OBJ_TYPE(
    1341                 :            :     mp_type_super,
    1342                 :            :     MP_QSTR_super,
    1343                 :            :     MP_TYPE_FLAG_NONE,
    1344                 :            :     make_new, super_make_new,
    1345                 :            :     print, super_print,
    1346                 :            :     attr, super_attr
    1347                 :            :     );
    1348                 :            : 
    1349                 :         58 : void mp_load_super_method(qstr attr, mp_obj_t *dest) {
    1350                 :         58 :     mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]};
    1351                 :         58 :     mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest);
    1352                 :         58 : }
    1353                 :            : 
    1354                 :            : /******************************************************************************/
    1355                 :            : // subclassing and built-ins specific to types
    1356                 :            : 
    1357                 :            : // object and classinfo should be type objects
    1358                 :            : // (but the function will fail gracefully if they are not)
    1359                 :     444975 : bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
    1360                 :     460029 :     for (;;) {
    1361         [ +  + ]:     460029 :         if (object == classinfo) {
    1362                 :            :             return true;
    1363                 :            :         }
    1364                 :            : 
    1365                 :            :         // not equivalent classes, keep searching base classes
    1366                 :            : 
    1367                 :            :         // object should always be a type object, but just return false if it's not
    1368   [ +  +  +  + ]:     240808 :         if (!mp_obj_is_type(object, &mp_type_type)) {
    1369                 :            :             return false;
    1370                 :            :         }
    1371                 :            : 
    1372                 :      22031 :         const mp_obj_type_t *self = MP_OBJ_TO_PTR(object);
    1373                 :            : 
    1374         [ +  + ]:      22031 :         if (!MP_OBJ_TYPE_HAS_SLOT(self, parent)) {
    1375                 :            :             // type has no parents
    1376                 :            :             return false;
    1377                 :            :         #if MICROPY_MULTIPLE_INHERITANCE
    1378         [ +  + ]:      15058 :         } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(self, parent))->type == &mp_type_tuple) {
    1379                 :            :             // get the base objects (they should be type objects)
    1380                 :          8 :             const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(self, parent);
    1381                 :          8 :             const mp_obj_t *item = parent_tuple->items;
    1382                 :          8 :             const mp_obj_t *top = item + parent_tuple->len - 1;
    1383                 :            : 
    1384                 :            :             // iterate through the base objects
    1385         [ +  + ]:         12 :             for (; item < top; ++item) {
    1386         [ +  + ]:          8 :                 if (mp_obj_is_subclass_fast(*item, classinfo)) {
    1387                 :            :                     return true;
    1388                 :            :                 }
    1389                 :            :             }
    1390                 :            : 
    1391                 :            :             // search last base (simple tail recursion elimination)
    1392                 :          4 :             object = *item;
    1393                 :            :         #endif
    1394                 :            :         } else {
    1395                 :            :             // type has 1 parent
    1396                 :            :             object = MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, parent));
    1397                 :            :         }
    1398                 :            :     }
    1399                 :            : }
    1400                 :            : 
    1401                 :        442 : STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) {
    1402                 :        442 :     size_t len;
    1403                 :        442 :     mp_obj_t *items;
    1404   [ +  +  +  + ]:        442 :     if (mp_obj_is_type(classinfo, &mp_type_type)) {
    1405                 :        308 :         len = 1;
    1406                 :        308 :         items = &classinfo;
    1407   [ -  +  -  +  :        134 :     } else if (mp_obj_is_type(classinfo, &mp_type_tuple)) {
          -  +  -  +  +  
                +  +  - ]
    1408                 :        130 :         mp_obj_tuple_get(classinfo, &len, &items);
    1409                 :            :     } else {
    1410                 :          4 :         mp_raise_TypeError(MP_ERROR_TEXT("issubclass() arg 2 must be a class or a tuple of classes"));
    1411                 :            :     }
    1412                 :            : 
    1413         [ +  + ]:        660 :     for (size_t i = 0; i < len; i++) {
    1414                 :            :         // We explicitly check for 'object' here since no-one explicitly derives from it
    1415   [ +  -  +  + ]:        534 :         if (items[i] == MP_OBJ_FROM_PTR(&mp_type_object) || mp_obj_is_subclass_fast(object, items[i])) {
    1416                 :            :             return mp_const_true;
    1417                 :            :         }
    1418                 :            :     }
    1419                 :            :     return mp_const_false;
    1420                 :            : }
    1421                 :            : 
    1422                 :         40 : STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) {
    1423   [ +  +  -  + ]:         40 :     if (!mp_obj_is_type(object, &mp_type_type)) {
    1424                 :          4 :         mp_raise_TypeError(MP_ERROR_TEXT("issubclass() arg 1 must be a class"));
    1425                 :            :     }
    1426                 :         36 :     return mp_obj_is_subclass(object, classinfo);
    1427                 :            : }
    1428                 :            : 
    1429                 :            : MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);
    1430                 :            : 
    1431                 :        406 : STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
    1432                 :        406 :     return mp_obj_is_subclass(MP_OBJ_FROM_PTR(mp_obj_get_type(object)), classinfo);
    1433                 :            : }
    1434                 :            : 
    1435                 :            : MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
    1436                 :            : 
    1437                 :         34 : mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type) {
    1438                 :         34 :     const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
    1439                 :            : 
    1440         [ +  + ]:         34 :     if (MP_OBJ_FROM_PTR(self_type) == native_type) {
    1441                 :            :         return self_in;
    1442         [ +  + ]:         18 :     } else if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) {
    1443                 :            :         return MP_OBJ_NULL;
    1444                 :            :     } else {
    1445                 :         10 :         mp_obj_instance_t *self = (mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in);
    1446                 :         10 :         return self->subobj[0];
    1447                 :            :     }
    1448                 :            : }
    1449                 :            : 
    1450                 :            : /******************************************************************************/
    1451                 :            : // staticmethod and classmethod types (probably should go in a different file)
    1452                 :            : 
    1453                 :         69 : STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    1454   [ +  +  -  + ]:         69 :     assert(self == &mp_type_staticmethod || self == &mp_type_classmethod);
    1455                 :            : 
    1456                 :         69 :     mp_arg_check_num(n_args, n_kw, 1, 1, false);
    1457                 :            : 
    1458                 :         69 :     mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t);
    1459                 :         69 :     *o = (mp_obj_static_class_method_t) {{self}, args[0]};
    1460                 :         69 :     return MP_OBJ_FROM_PTR(o);
    1461                 :            : }
    1462                 :            : 
    1463                 :            : MP_DEFINE_CONST_OBJ_TYPE(
    1464                 :            :     mp_type_staticmethod,
    1465                 :            :     MP_QSTR_staticmethod,
    1466                 :            :     MP_TYPE_FLAG_NONE,
    1467                 :            :     make_new, static_class_method_make_new
    1468                 :            :     );
    1469                 :            : 
    1470                 :            : MP_DEFINE_CONST_OBJ_TYPE(
    1471                 :            :     mp_type_classmethod,
    1472                 :            :     MP_QSTR_classmethod,
    1473                 :            :     MP_TYPE_FLAG_NONE,
    1474                 :            :     make_new, static_class_method_make_new
    1475                 :            :     );

Generated by: LCOV version 1.15-5-g462f71d