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