LCOV - code coverage report
Current view: top level - py - objtype.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-7-g548babf8a.info Lines: 565 565 100.0 %
Date: 2024-10-30 09:06:48 Functions: 33 33 100.0 %
Branches: 384 445 86.3 %

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

Generated by: LCOV version 1.15-5-g462f71d