LCOV - code coverage report
Current view: top level - py - objtype.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-315-g20a86eff5.info Lines: 562 562 100.0 %
Date: 2024-03-29 10:17:09 Functions: 33 33 100.0 %
Branches: 381 444 85.8 %

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

Generated by: LCOV version 1.15-5-g462f71d