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 : 4632 : static int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
54 : 4632 : int count = 0;
55 : 6102 : for (;;) {
56 [ + + ]: 6102 : if (type == &mp_type_object) {
57 : : // Not a "real" type, end search here.
58 : : return count;
59 [ + + ]: 5626 : } 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 [ + + ]: 4750 : } 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 : 2691 : mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) {
101 : 2691 : size_t num_native_bases = instance_count_native_bases(class, native_base);
102 [ - + ]: 2691 : assert(num_native_bases < 2);
103 : 2691 : mp_obj_instance_t *o = mp_obj_malloc_var(mp_obj_instance_t, subobj, mp_obj_t, num_native_bases, class);
104 : 2691 : 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 [ + + ]: 2691 : if (num_native_bases != 0) {
109 : 480 : o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
110 : : }
111 : 2691 : 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 : 1759176 : static void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {
137 [ - + ]: 1759176 : assert(lookup->dest[0] == MP_OBJ_NULL);
138 [ - + ]: 1759176 : assert(lookup->dest[1] == MP_OBJ_NULL);
139 : 1787496 : for (;;) {
140 : 1787496 : 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 [ + + + + ]: 1787496 : 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 [ + + ]: 1786662 : if (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) {
158 : : // search locals_dict (the set of methods/attributes)
159 [ - + ]: 1786166 : assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(type, locals_dict)))); // MicroPython restriction, for now
160 : 1786267 : mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->map;
161 : 1786267 : mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
162 [ + + ]: 1786267 : if (elem != NULL) {
163 [ + + ]: 1713588 : 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 : 869 : const mp_obj_type_t *org_type = (const mp_obj_type_t *)lookup->obj;
167 : 869 : mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest);
168 : : } else {
169 : 1712719 : mp_obj_instance_t *obj = lookup->obj;
170 : 1712719 : mp_obj_t obj_obj;
171 [ + + + + : 1712719 : 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 : 1712717 : 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 : 1713586 : 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 [ + + + + : 73175 : 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 [ + + ]: 73113 : 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 [ + + ]: 28850 : } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
215 : 6870 : const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
216 : 6870 : const mp_obj_t *item = parent_tuple->items;
217 : 6870 : const mp_obj_t *top = item + parent_tuple->len - 1;
218 [ + + ]: 13652 : for (; item < top; ++item) {
219 [ + - - + ]: 6870 : assert(mp_obj_is_type(*item, &mp_type_type));
220 : 6870 : mp_obj_type_t *bt = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
221 [ + + ]: 6870 : if (bt == &mp_type_object) {
222 : : // Not a "real" type
223 : 6 : continue;
224 : : }
225 : 6864 : mp_obj_class_lookup(lookup, bt);
226 [ + + ]: 6864 : if (lookup->dest[0] != MP_OBJ_NULL) {
227 : : return;
228 : : }
229 : : }
230 : :
231 : : // search last base (simple tail recursion elimination)
232 [ + - - + ]: 6782 : 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 [ + + ]: 28762 : 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 : 2699 : 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 [ - + ]: 2699 : assert(mp_obj_is_instance_type(self));
289 : :
290 : : // look for __new__ function
291 : 2699 : mp_obj_t init_fn[2] = {MP_OBJ_NULL};
292 : 2699 : 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 : 2699 : mp_obj_class_lookup(&lookup, self);
300 : :
301 : 2699 : const mp_obj_type_t *native_base = NULL;
302 : 2699 : mp_obj_instance_t *o;
303 [ + + ]: 2699 : 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 : 2675 : 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 : 2679 : init_fn[0] = init_fn[1] = MP_OBJ_NULL;
343 : 2679 : lookup.obj = o;
344 : 2679 : lookup.attr = MP_QSTR___init__;
345 : 2679 : lookup.slot_offset = 0;
346 : 2679 : mp_obj_class_lookup(&lookup, self);
347 [ + + ]: 2679 : 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 [ + + + + ]: 2675 : 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 : 3547540 : 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 [ - + ]: 3547540 : assert(mp_obj_is_instance_type(mp_obj_get_type(self_in)));
589 : 3547540 : 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 : 3547540 : mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
593 [ + + ]: 3547540 : if (elem != NULL) {
594 : : // object member, always treated as a value
595 : 2118409 : dest[0] = elem->value;
596 : 3520530 : return;
597 : : }
598 : : #if MICROPY_CPYTHON_COMPAT
599 [ + + ]: 1429131 : 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 : 1429107 : struct class_lookup_data lookup = {
612 : : .obj = self,
613 : : .attr = attr,
614 : : .slot_offset = 0,
615 : : .dest = dest,
616 : : .is_type = false,
617 : : };
618 : 1429107 : mp_obj_class_lookup(&lookup, self->base.type);
619 : 1429105 : mp_obj_t member = dest[0];
620 [ + + ]: 1429105 : if (member != MP_OBJ_NULL) {
621 [ + + ]: 1401969 : 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 [ - + - + : 180 : 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 : 74 : const mp_obj_t *proxy = mp_obj_property_get(member);
636 [ + + ]: 74 : if (proxy[0] == mp_const_none) {
637 : 4 : mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT("unreadable attribute"));
638 : : } else {
639 : 70 : dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
640 : : }
641 : 70 : 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 [ + + ]: 27136 : if (attr != MP_QSTR___getattr__) {
663 : : #if MICROPY_PY_DELATTR_SETATTR
664 : : // If the requested attr is __setattr__/__delattr__ then don't delegate the lookup
665 : : // to __getattr__. If we followed CPython's behaviour then __setattr__/__delattr__
666 : : // would have already been found in the "object" base class.
667 [ + + ]: 13638 : if (attr == MP_QSTR___setattr__ || attr == MP_QSTR___delattr__) {
668 : 132 : return;
669 : : }
670 : : #endif
671 : :
672 : 13550 : mp_obj_t dest2[3];
673 : 13550 : mp_load_method_maybe(self_in, MP_QSTR___getattr__, dest2);
674 [ + + ]: 13550 : if (dest2[0] != MP_OBJ_NULL) {
675 : : // __getattr__ exists, call it and return its result
676 : 68 : dest2[2] = MP_OBJ_NEW_QSTR(attr);
677 : 68 : dest[0] = mp_call_method_n_kw(1, 0, dest2);
678 : 44 : return;
679 : : }
680 : : }
681 : : }
682 : :
683 : 644670 : static bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
684 : 644670 : mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
685 : :
686 [ + + ]: 644670 : if (!(self->base.type->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
687 : : // Class doesn't have any special accessors so skip their checks
688 : 644522 : goto skip_special_accessors;
689 : : }
690 : :
691 : : #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS
692 : : // With property and/or descriptors enabled we need to do a lookup
693 : : // first in the class dict for the attribute to see if the store should
694 : : // be delegated.
695 : 148 : mp_obj_t member[2] = {MP_OBJ_NULL};
696 : 148 : struct class_lookup_data lookup = {
697 : : .obj = self,
698 : : .attr = attr,
699 : : .slot_offset = 0,
700 : : .dest = member,
701 : : .is_type = false,
702 : : };
703 : 148 : mp_obj_class_lookup(&lookup, self->base.type);
704 : :
705 [ + + ]: 148 : if (member[0] != MP_OBJ_NULL) {
706 : : #if MICROPY_PY_BUILTINS_PROPERTY
707 [ - + - + : 64 : if (mp_obj_is_type(member[0], &mp_type_property)) {
- + - + +
- + + ]
708 : : // attribute exists and is a property; delegate the store/delete
709 : : // Note: This is an optimisation for code size and execution time.
710 : : // The proper way to do it is have the functionality just below in
711 : : // a __set__/__delete__ method of the property object, and then it
712 : : // would be called by the descriptor code down below. But that way
713 : : // requires overhead for the nested mp_call's and overhead for
714 : : // the code.
715 : 48 : const mp_obj_t *proxy = mp_obj_property_get(member[0]);
716 : 48 : mp_obj_t dest[2] = {self_in, value};
717 [ + + ]: 48 : if (value == MP_OBJ_NULL) {
718 : : // delete attribute
719 [ + + ]: 12 : if (proxy[2] == mp_const_none) {
720 : : // TODO better error message?
721 : : return false;
722 : : } else {
723 : 8 : mp_call_function_n_kw(proxy[2], 1, 0, dest);
724 : 8 : return true;
725 : : }
726 : : } else {
727 : : // store attribute
728 [ + + ]: 36 : if (proxy[1] == mp_const_none) {
729 : : // TODO better error message?
730 : : return false;
731 : : } else {
732 : 28 : mp_call_function_n_kw(proxy[1], 2, 0, dest);
733 : 28 : return true;
734 : : }
735 : : }
736 : : }
737 : : #endif
738 : :
739 : : #if MICROPY_PY_DESCRIPTORS
740 : : // found a class attribute; if it has a __set__/__delete__ method then
741 : : // call it with the class instance (and value) as arguments
742 [ + + ]: 16 : if (value == MP_OBJ_NULL) {
743 : : // delete attribute
744 : 8 : mp_obj_t attr_delete_method[3];
745 : 8 : mp_load_method_maybe(member[0], MP_QSTR___delete__, attr_delete_method);
746 [ + + ]: 8 : if (attr_delete_method[0] != MP_OBJ_NULL) {
747 : 4 : attr_delete_method[2] = self_in;
748 : 4 : mp_call_method_n_kw(1, 0, attr_delete_method);
749 : 4 : return true;
750 : : }
751 : : } else {
752 : : // store attribute
753 : 8 : mp_obj_t attr_set_method[4];
754 : 8 : mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method);
755 [ + + ]: 8 : if (attr_set_method[0] != MP_OBJ_NULL) {
756 : 4 : attr_set_method[2] = self_in;
757 : 4 : attr_set_method[3] = value;
758 : 4 : mp_call_method_n_kw(2, 0, attr_set_method);
759 : 4 : return true;
760 : : }
761 : : }
762 : : #endif
763 : : }
764 : : #endif
765 : :
766 : : #if MICROPY_PY_DELATTR_SETATTR
767 [ + + ]: 92 : if (value == MP_OBJ_NULL) {
768 : : // delete attribute
769 : : // try __delattr__ first
770 : 20 : mp_obj_t attr_delattr_method[3];
771 : 20 : mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method);
772 [ + - ]: 20 : if (attr_delattr_method[0] != MP_OBJ_NULL) {
773 : : // __delattr__ exists, so call it
774 : 20 : attr_delattr_method[2] = MP_OBJ_NEW_QSTR(attr);
775 : 20 : mp_call_method_n_kw(1, 0, attr_delattr_method);
776 : 20 : return true;
777 : : }
778 : : } else {
779 : : // store attribute
780 : : // try __setattr__ first
781 : 72 : mp_obj_t attr_setattr_method[4];
782 : 72 : mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method);
783 [ + + ]: 72 : if (attr_setattr_method[0] != MP_OBJ_NULL) {
784 : : // __setattr__ exists, so call it
785 : 16 : attr_setattr_method[2] = MP_OBJ_NEW_QSTR(attr);
786 : 16 : attr_setattr_method[3] = value;
787 : 16 : mp_call_method_n_kw(2, 0, attr_setattr_method);
788 : 16 : return true;
789 : : }
790 : : }
791 : : #endif
792 : :
793 : 644578 : skip_special_accessors:
794 : :
795 [ + + ]: 644578 : if (value == MP_OBJ_NULL) {
796 : : // delete attribute
797 : 16 : mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
798 : 16 : return elem != NULL;
799 : : } else {
800 : : // store attribute
801 : 644562 : mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
802 : 644560 : return true;
803 : : }
804 : : }
805 : :
806 : 4192009 : static void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
807 [ + + ]: 4192009 : if (dest[0] == MP_OBJ_NULL) {
808 : 3547540 : mp_obj_instance_load_attr(self_in, attr, dest);
809 : : } else {
810 [ + + ]: 644469 : if (mp_obj_instance_store_attr(self_in, attr, dest[1])) {
811 : 644648 : dest[0] = MP_OBJ_NULL; // indicate success
812 : : }
813 : : }
814 : 4192178 : }
815 : :
816 : 148 : static mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
817 : 148 : mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
818 : 148 : mp_obj_t member[4] = {MP_OBJ_NULL, MP_OBJ_NULL, index, value};
819 : 148 : struct class_lookup_data lookup = {
820 : : .obj = self,
821 : : .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(subscr),
822 : : .dest = member,
823 : : .is_type = false,
824 : : };
825 [ + + ]: 148 : if (value == MP_OBJ_NULL) {
826 : : // delete item
827 : 8 : lookup.attr = MP_QSTR___delitem__;
828 [ + + ]: 140 : } else if (value == MP_OBJ_SENTINEL) {
829 : : // load item
830 : 128 : lookup.attr = MP_QSTR___getitem__;
831 : : } else {
832 : : // store item
833 : 12 : lookup.attr = MP_QSTR___setitem__;
834 : : }
835 : 148 : mp_obj_class_lookup(&lookup, self->base.type);
836 [ + + ]: 148 : if (member[0] == MP_OBJ_SENTINEL) {
837 : 16 : return mp_obj_subscr(self->subobj[0], index, value);
838 [ + + ]: 132 : } else if (member[0] != MP_OBJ_NULL) {
839 [ + + ]: 128 : size_t n_args = value == MP_OBJ_NULL || value == MP_OBJ_SENTINEL ? 1 : 2;
840 : 128 : mp_obj_t ret = mp_call_method_n_kw(n_args, 0, member);
841 [ + + ]: 128 : if (value == MP_OBJ_SENTINEL) {
842 : : return ret;
843 : : } else {
844 : 16 : return mp_const_none;
845 : : }
846 : : } else {
847 : : return MP_OBJ_NULL; // op not supported
848 : : }
849 : : }
850 : :
851 : 48 : static mp_obj_t mp_obj_instance_get_call(mp_obj_t self_in, mp_obj_t *member) {
852 : 48 : mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
853 : 48 : struct class_lookup_data lookup = {
854 : : .obj = self,
855 : : .attr = MP_QSTR___call__,
856 : : .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(call),
857 : : .dest = member,
858 : : .is_type = false,
859 : : };
860 : 48 : mp_obj_class_lookup(&lookup, self->base.type);
861 : 48 : return member[0];
862 : : }
863 : :
864 : 12 : bool mp_obj_instance_is_callable(mp_obj_t self_in) {
865 : 12 : mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
866 : 12 : return mp_obj_instance_get_call(self_in, member) != MP_OBJ_NULL;
867 : : }
868 : :
869 : 36 : mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
870 : 36 : mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
871 : 36 : mp_obj_t call = mp_obj_instance_get_call(self_in, member);
872 [ + + ]: 36 : if (call == MP_OBJ_NULL) {
873 : : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
874 : : mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
875 : : #else
876 : 4 : mp_raise_msg_varg(&mp_type_TypeError,
877 : 4 : MP_ERROR_TEXT("'%s' object isn't callable"), mp_obj_get_type_str(self_in));
878 : : #endif
879 : : }
880 : 32 : mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
881 [ + + ]: 32 : if (call == MP_OBJ_SENTINEL) {
882 : 4 : return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
883 : : }
884 : :
885 : 28 : return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args);
886 : : }
887 : :
888 : : // Note that iter_buf may be NULL, and needs to be allocated if needed
889 : 308126 : mp_obj_t mp_obj_instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
890 : 308126 : mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
891 : 308126 : mp_obj_t member[2] = {MP_OBJ_NULL};
892 : 308126 : struct class_lookup_data lookup = {
893 : : .obj = self,
894 : : .attr = MP_QSTR___iter__,
895 : : .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(iter),
896 : : .dest = member,
897 : : .is_type = false,
898 : : };
899 : 308126 : mp_obj_class_lookup(&lookup, self->base.type);
900 [ + + ]: 308126 : if (member[0] == MP_OBJ_NULL) {
901 : : return MP_OBJ_NULL;
902 [ + + ]: 308098 : } else if (member[0] == MP_OBJ_SENTINEL) {
903 : 16 : const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
904 [ + + ]: 16 : if (type->flags & MP_TYPE_FLAG_ITER_IS_ITERNEXT) {
905 : 8 : return self->subobj[0];
906 : : } else {
907 [ + + ]: 8 : if (iter_buf == NULL) {
908 : 4 : iter_buf = m_new_obj(mp_obj_iter_buf_t);
909 : : }
910 : 8 : return ((mp_getiter_fun_t)MP_OBJ_TYPE_GET_SLOT(type, iter))(self->subobj[0], iter_buf);
911 : : }
912 : : } else {
913 : 308082 : return mp_call_method_n_kw(0, 0, member);
914 : : }
915 : : }
916 : :
917 : 38 : static mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
918 : 38 : mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
919 : 38 : mp_obj_t member[2] = {MP_OBJ_NULL};
920 : 38 : struct class_lookup_data lookup = {
921 : : .obj = self,
922 : : .attr = MP_QSTR_, // don't actually look for a method
923 : : .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(buffer),
924 : : .dest = member,
925 : : .is_type = false,
926 : : };
927 : 38 : mp_obj_class_lookup(&lookup, self->base.type);
928 [ + + ]: 38 : if (member[0] == MP_OBJ_SENTINEL) {
929 : 18 : const mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
930 : 18 : return MP_OBJ_TYPE_GET_SLOT(type, buffer)(self->subobj[0], bufinfo, flags);
931 : : } else {
932 : : return 1; // object does not support buffer protocol
933 : : }
934 : : }
935 : :
936 : : /******************************************************************************/
937 : : // type object
938 : : // - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
939 : : // - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object
940 : : // - creating a new class (a new type) creates a new mp_obj_type_t
941 : :
942 : : #if ENABLE_SPECIAL_ACCESSORS
943 : 6894 : static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
944 : : #if MICROPY_PY_DELATTR_SETATTR
945 [ + + ]: 6894 : if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) {
946 : : return true;
947 : : }
948 : : #endif
949 : : #if MICROPY_PY_BUILTINS_PROPERTY
950 [ - + - + : 6878 : if (mp_obj_is_type(value, &mp_type_property)) {
- + - + +
+ + + ]
951 : : return true;
952 : : }
953 : : #endif
954 : : #if MICROPY_PY_DESCRIPTORS
955 : : static const uint8_t to_check[] = {
956 : : MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__,
957 : : };
958 [ + + ]: 27308 : for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) {
959 : 20482 : mp_obj_t dest_temp[2];
960 : 20482 : mp_load_method_protected(value, to_check[i], dest_temp, true);
961 [ + + ]: 20482 : if (dest_temp[0] != MP_OBJ_NULL) {
962 : 4 : return true;
963 : : }
964 : : }
965 : : #endif
966 : : return false;
967 : : }
968 : : #endif
969 : :
970 : 532 : static void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
971 : 532 : (void)kind;
972 : 532 : mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
973 : 532 : mp_printf(print, "<class '%q'>", self->name);
974 : 532 : }
975 : :
976 : 6793 : static mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
977 : 6793 : (void)type_in;
978 : :
979 : 6793 : mp_arg_check_num(n_args, n_kw, 1, 3, false);
980 : :
981 [ + + + ]: 6789 : switch (n_args) {
982 : 5118 : case 1:
983 : 5118 : return MP_OBJ_FROM_PTR(mp_obj_get_type(args[0]));
984 : :
985 : 1667 : case 3:
986 : : // args[0] = name
987 : : // args[1] = bases tuple
988 : : // args[2] = locals dict
989 : 1667 : return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]);
990 : :
991 : : default:
992 : 4 : mp_raise_TypeError(MP_ERROR_TEXT("type takes 1 or 3 arguments"));
993 : : }
994 : : }
995 : :
996 : 422055 : static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
997 : : // instantiate an instance of a class
998 : :
999 : 422055 : mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
1000 : :
1001 [ + + ]: 422055 : if (!MP_OBJ_TYPE_HAS_SLOT(self, make_new)) {
1002 : : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
1003 : : mp_raise_TypeError(MP_ERROR_TEXT("can't create instance"));
1004 : : #else
1005 : 2 : mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("can't create '%q' instances"), self->name);
1006 : : #endif
1007 : : }
1008 : :
1009 : : // make new instance
1010 : 422053 : mp_obj_t o = MP_OBJ_TYPE_GET_SLOT(self, make_new)(self, n_args, n_kw, args);
1011 : :
1012 : : // return new instance
1013 : 421562 : return o;
1014 : : }
1015 : :
1016 : 7783 : static void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
1017 [ + - - + ]: 7783 : assert(mp_obj_is_type(self_in, &mp_type_type));
1018 : 7783 : mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
1019 : :
1020 [ + + ]: 7783 : if (dest[0] == MP_OBJ_NULL) {
1021 : : // load attribute
1022 : : #if MICROPY_CPYTHON_COMPAT
1023 [ + + ]: 7685 : if (attr == MP_QSTR___name__) {
1024 : 82 : dest[0] = MP_OBJ_NEW_QSTR(self->name);
1025 : 198 : return;
1026 : : }
1027 : : #if MICROPY_CPYTHON_COMPAT
1028 [ + + ]: 7603 : if (attr == MP_QSTR___dict__) {
1029 : : // Returns a read-only dict of the class attributes.
1030 : : // If the internal locals is not fixed, a copy will be created.
1031 [ + + ]: 32 : const mp_obj_dict_t *dict = MP_OBJ_TYPE_GET_SLOT_OR_NULL(self, locals_dict);
1032 [ - + ]: 28 : if (!dict) {
1033 : 4 : dict = &mp_const_empty_dict_obj;
1034 : : }
1035 [ + + ]: 32 : if (dict->map.is_fixed) {
1036 : 20 : dest[0] = MP_OBJ_FROM_PTR(dict);
1037 : : } else {
1038 : 12 : dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(dict));
1039 : 12 : mp_obj_dict_t *dict_copy = MP_OBJ_TO_PTR(dest[0]);
1040 : 12 : dict_copy->map.is_fixed = 1;
1041 : : }
1042 : 32 : return;
1043 : : }
1044 : : #endif
1045 [ + + ]: 7571 : if (attr == MP_QSTR___bases__) {
1046 [ + + ]: 84 : if (self == &mp_type_object) {
1047 : 8 : dest[0] = mp_const_empty_tuple;
1048 : 8 : return;
1049 : : }
1050 [ + + ]: 76 : mp_obj_t parent_obj = MP_OBJ_TYPE_HAS_SLOT(self, parent) ? MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, parent)) : MP_OBJ_FROM_PTR(&mp_type_object);
1051 : : #if MICROPY_MULTIPLE_INHERITANCE
1052 [ - + - + : 76 : if (mp_obj_is_type(parent_obj, &mp_type_tuple)) {
- + - + +
- + + ]
1053 : 20 : dest[0] = parent_obj;
1054 : 20 : return;
1055 : : }
1056 : : #endif
1057 : 56 : dest[0] = mp_obj_new_tuple(1, &parent_obj);
1058 : 56 : return;
1059 : : }
1060 : : #endif
1061 : 7487 : struct class_lookup_data lookup = {
1062 : : .obj = (mp_obj_instance_t *)self,
1063 : : .attr = attr,
1064 : : .slot_offset = 0,
1065 : : .dest = dest,
1066 : : .is_type = true,
1067 : : };
1068 : 7487 : mp_obj_class_lookup(&lookup, self);
1069 : : } else {
1070 : : // delete/store attribute
1071 : :
1072 [ + - ]: 98 : if (MP_OBJ_TYPE_HAS_SLOT(self, locals_dict)) {
1073 [ - + ]: 98 : assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, locals_dict)))); // MicroPython restriction, for now
1074 : 98 : mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(self, locals_dict)->map;
1075 [ + + ]: 98 : if (locals_map->is_fixed) {
1076 : : // can't apply delete/store to a fixed map
1077 : : return;
1078 : : }
1079 [ + + ]: 90 : if (dest[1] == MP_OBJ_NULL) {
1080 : : // delete attribute
1081 : 8 : mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
1082 [ + + ]: 8 : if (elem != NULL) {
1083 : 4 : dest[0] = MP_OBJ_NULL; // indicate success
1084 : : }
1085 : : } else {
1086 : : #if ENABLE_SPECIAL_ACCESSORS
1087 : : // Check if we add any special accessor methods with this store
1088 [ + + ]: 82 : if (!(self->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
1089 [ + + ]: 74 : if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) {
1090 [ + + ]: 10 : if (self->flags & MP_TYPE_FLAG_IS_SUBCLASSED) {
1091 : : // This class is already subclassed so can't have special accessors added
1092 : 2 : mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT("can't add special method to already-subclassed class"));
1093 : : }
1094 : 8 : self->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
1095 : : }
1096 : : }
1097 : : #endif
1098 : :
1099 : : // store attribute
1100 : 80 : mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
1101 : 80 : elem->value = dest[1];
1102 : 80 : dest[0] = MP_OBJ_NULL; // indicate success
1103 : : }
1104 : : }
1105 : : }
1106 : : }
1107 : :
1108 : : MP_DEFINE_CONST_OBJ_TYPE(
1109 : : mp_type_type,
1110 : : MP_QSTR_type,
1111 : : MP_TYPE_FLAG_NONE,
1112 : : make_new, type_make_new,
1113 : : print, type_print,
1114 : : call, type_call,
1115 : : attr, type_attr
1116 : : );
1117 : :
1118 : 1661 : mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
1119 : : // Verify input objects have expected type
1120 [ - + - + : 1661 : if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) {
- + - + +
+ - + ]
1121 : 4 : mp_raise_TypeError(NULL);
1122 : : }
1123 [ + + ]: 1657 : if (!mp_obj_is_dict_or_ordereddict(locals_dict)) {
1124 : 4 : mp_raise_TypeError(NULL);
1125 : : }
1126 : :
1127 : : // TODO might need to make a copy of locals_dict; at least that's how CPython does it
1128 : :
1129 : : // Basic validation of base classes
1130 : 1653 : uint16_t base_flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE
1131 : : | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE
1132 : : | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST
1133 : : | MP_TYPE_FLAG_ITER_IS_GETITER
1134 : : | MP_TYPE_FLAG_INSTANCE_TYPE;
1135 : 1653 : size_t bases_len;
1136 : 1653 : mp_obj_t *bases_items;
1137 : 1653 : mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items);
1138 [ + + ]: 2197 : for (size_t i = 0; i < bases_len; i++) {
1139 [ + + - + ]: 552 : if (!mp_obj_is_type(bases_items[i], &mp_type_type)) {
1140 : 4 : mp_raise_TypeError(NULL);
1141 : : }
1142 : 548 : mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);
1143 : : // TODO: Verify with CPy, tested on function type
1144 [ + + ]: 548 : if (!MP_OBJ_TYPE_HAS_SLOT(t, make_new)) {
1145 : : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
1146 : : mp_raise_TypeError(MP_ERROR_TEXT("type isn't an acceptable base type"));
1147 : : #else
1148 : 4 : mp_raise_msg_varg(&mp_type_TypeError,
1149 : 4 : MP_ERROR_TEXT("type '%q' isn't an acceptable base type"), t->name);
1150 : : #endif
1151 : : }
1152 : : #if ENABLE_SPECIAL_ACCESSORS
1153 [ + + ]: 544 : if (mp_obj_is_instance_type(t)) {
1154 : 148 : t->flags |= MP_TYPE_FLAG_IS_SUBCLASSED;
1155 : 148 : base_flags |= t->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
1156 : : }
1157 : : #endif
1158 : : }
1159 : :
1160 : 1645 : const void *base_protocol = NULL;
1161 [ + + ]: 1645 : if (bases_len > 0) {
1162 [ + + ]: 486 : base_protocol = MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_type_t *)MP_OBJ_TO_PTR(bases_items[0])), protocol);
1163 : : }
1164 : :
1165 : : // Allocate a variable-sized mp_obj_type_t with as many slots as we need
1166 : : // (currently 10, plus 1 for base, plus 1 for base-protocol).
1167 : : // Note: mp_obj_type_t is (2 + 3 + #slots) words, so going from 11 to 12 slots
1168 : : // moves from 4 to 5 gc blocks.
1169 [ + + ]: 2804 : mp_obj_type_t *o = m_new_obj_var0(mp_obj_type_t, slots, void *, 10 + (bases_len ? 1 : 0) + (base_protocol ? 1 : 0));
1170 : 1645 : o->base.type = &mp_type_type;
1171 : 1645 : o->flags = base_flags;
1172 : 1645 : o->name = name;
1173 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, make_new, mp_obj_instance_make_new, 0);
1174 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, print, instance_print, 1);
1175 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, call, mp_obj_instance_call, 2);
1176 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, unary_op, instance_unary_op, 3);
1177 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, binary_op, instance_binary_op, 4);
1178 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, attr, mp_obj_instance_attr, 5);
1179 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, subscr, instance_subscr, 6);
1180 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, iter, mp_obj_instance_getiter, 7);
1181 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, buffer, instance_get_buffer, 8);
1182 : :
1183 : 1645 : mp_obj_dict_t *locals_ptr = MP_OBJ_TO_PTR(locals_dict);
1184 : 1645 : MP_OBJ_TYPE_SET_SLOT(o, locals_dict, locals_ptr, 9);
1185 : :
1186 [ + + ]: 1645 : if (bases_len > 0) {
1187 [ + + ]: 486 : if (bases_len >= 2) {
1188 : : #if MICROPY_MULTIPLE_INHERITANCE
1189 : 58 : MP_OBJ_TYPE_SET_SLOT(o, parent, MP_OBJ_TO_PTR(bases_tuple), 10);
1190 : : #else
1191 : : mp_raise_NotImplementedError(MP_ERROR_TEXT("multiple inheritance not supported"));
1192 : : #endif
1193 : : } else {
1194 : 428 : MP_OBJ_TYPE_SET_SLOT(o, parent, MP_OBJ_TO_PTR(bases_items[0]), 10);
1195 : : }
1196 : :
1197 : : // Inherit protocol from a base class. This allows to define an
1198 : : // abstract base class which would translate C-level protocol to
1199 : : // Python method calls, and any subclass inheriting from it will
1200 : : // support this feature.
1201 [ + + ]: 486 : if (base_protocol) {
1202 : 68 : MP_OBJ_TYPE_SET_SLOT(o, protocol, base_protocol, 11);
1203 : : }
1204 : : }
1205 : :
1206 : : #if ENABLE_SPECIAL_ACCESSORS
1207 : : // Check if the class has any special accessor methods
1208 [ + + ]: 1645 : if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
1209 [ + + ]: 9287 : for (size_t i = 0; i < locals_ptr->map.alloc; i++) {
1210 [ + + ]: 7716 : if (mp_map_slot_is_filled(&locals_ptr->map, i)) {
1211 : 6820 : const mp_map_elem_t *elem = &locals_ptr->map.table[i];
1212 [ + + ]: 6820 : if (check_for_special_accessors(elem->key, elem->value)) {
1213 : 58 : o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
1214 : 58 : break;
1215 : : }
1216 : : }
1217 : : }
1218 : : }
1219 : : #endif
1220 : :
1221 : 1645 : const mp_obj_type_t *native_base;
1222 : 1645 : size_t num_native_bases = instance_count_native_bases(o, &native_base);
1223 [ + + ]: 1645 : if (num_native_bases > 1) {
1224 : 4 : mp_raise_TypeError(MP_ERROR_TEXT("multiple bases have instance lay-out conflict"));
1225 : : }
1226 : :
1227 : 1641 : mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(o, locals_dict)->map;
1228 : 1641 : mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
1229 [ + + ]: 1641 : if (elem != NULL) {
1230 : : // __new__ slot exists; check if it is a function
1231 [ + - + - ]: 24 : if (mp_obj_is_fun(elem->value)) {
1232 : : // __new__ is a function, wrap it in a staticmethod decorator
1233 : 24 : elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value);
1234 : : }
1235 : : }
1236 : :
1237 : 1641 : return MP_OBJ_FROM_PTR(o);
1238 : : }
1239 : :
1240 : : /******************************************************************************/
1241 : : // super object
1242 : :
1243 : : typedef struct _mp_obj_super_t {
1244 : : mp_obj_base_t base;
1245 : : mp_obj_t type;
1246 : : mp_obj_t obj;
1247 : : } mp_obj_super_t;
1248 : :
1249 : 4 : static void super_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
1250 : 4 : (void)kind;
1251 : 4 : mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in);
1252 : 4 : mp_print_str(print, "<super: ");
1253 : 4 : mp_obj_print_helper(print, self->type, PRINT_STR);
1254 : 4 : mp_print_str(print, ", ");
1255 : 4 : mp_obj_print_helper(print, self->obj, PRINT_STR);
1256 : 4 : mp_print_str(print, ">");
1257 : 4 : }
1258 : :
1259 : 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) {
1260 : 68 : (void)type_in;
1261 : : // 0 arguments are turned into 2 in the compiler
1262 : : // 1 argument is not yet implemented
1263 : 68 : mp_arg_check_num(n_args, n_kw, 2, 2, false);
1264 : :
1265 : : // Per CPython: "If the second argument is an object, isinstance(obj, type) must be true.
1266 : : // If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods)."
1267 : 68 : const mp_obj_type_t *second_arg_type = mp_obj_get_type(args[1]);
1268 [ + + ]: 68 : mp_obj_t second_arg_obj = second_arg_type == &mp_type_type ? args[1] : MP_OBJ_FROM_PTR(second_arg_type);
1269 [ + + ]: 68 : if (mp_obj_is_subclass(second_arg_obj, args[0]) == mp_const_false) {
1270 : 8 : mp_raise_TypeError(NULL);
1271 : : }
1272 : :
1273 : 52 : mp_obj_super_t *o = m_new_obj(mp_obj_super_t);
1274 : 52 : *o = (mp_obj_super_t) {{type_in}, args[0], args[1]};
1275 : 52 : return MP_OBJ_FROM_PTR(o);
1276 : : }
1277 : :
1278 : 144 : static void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
1279 [ + + ]: 144 : if (dest[0] != MP_OBJ_NULL) {
1280 : : // not load attribute
1281 : 96 : return;
1282 : : }
1283 : :
1284 [ + - - + ]: 136 : assert(mp_obj_is_type(self_in, &mp_type_super));
1285 : 136 : mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in);
1286 : :
1287 [ + - - + ]: 136 : assert(mp_obj_is_type(self->type, &mp_type_type));
1288 : :
1289 : 136 : mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type);
1290 : :
1291 : 136 : struct class_lookup_data lookup = {
1292 : 136 : .obj = MP_OBJ_TO_PTR(self->obj),
1293 : : .attr = attr,
1294 : : .slot_offset = 0,
1295 : : .dest = dest,
1296 : : .is_type = false,
1297 : : };
1298 : :
1299 : : // Allow a call super().__init__() to reach any native base classes.
1300 [ + + ]: 136 : if (attr == MP_QSTR___init__) {
1301 : 72 : lookup.slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(make_new);
1302 : : }
1303 : :
1304 [ + + ]: 136 : if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
1305 : : // no parents, do nothing
1306 : : #if MICROPY_MULTIPLE_INHERITANCE
1307 [ + + ]: 108 : } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
1308 : 16 : const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
1309 : 16 : size_t len = parent_tuple->len;
1310 : 16 : const mp_obj_t *items = parent_tuple->items;
1311 [ + + ]: 40 : for (size_t i = 0; i < len; i++) {
1312 [ + - - + ]: 28 : assert(mp_obj_is_type(items[i], &mp_type_type));
1313 [ + + ]: 28 : if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) {
1314 : : // The "object" type will be searched at the end of this function,
1315 : : // and we don't want to lookup native methods in object.
1316 : 12 : continue;
1317 : : }
1318 : :
1319 : 16 : mp_obj_class_lookup(&lookup, (mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]));
1320 [ + + ]: 16 : if (dest[0] != MP_OBJ_NULL) {
1321 : : break;
1322 : : }
1323 : : }
1324 : : #endif
1325 [ + + ]: 92 : } else if (MP_OBJ_TYPE_GET_SLOT(type, parent) != &mp_type_object) {
1326 : 84 : mp_obj_class_lookup(&lookup, MP_OBJ_TYPE_GET_SLOT(type, parent));
1327 : : }
1328 : :
1329 [ + + ]: 136 : if (dest[0] != MP_OBJ_NULL) {
1330 [ + + ]: 88 : if (dest[0] == MP_OBJ_SENTINEL) {
1331 : : // Looked up native __init__ so defer to it
1332 : 44 : dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
1333 : 44 : dest[1] = self->obj;
1334 : : }
1335 : 88 : return;
1336 : : }
1337 : :
1338 : : // Reset slot_offset so we don't look up any native methods in object,
1339 : : // because object never takes up the native base-class slot.
1340 : 48 : lookup.slot_offset = 0;
1341 : :
1342 : 48 : mp_obj_class_lookup(&lookup, &mp_type_object);
1343 : : }
1344 : :
1345 : : MP_DEFINE_CONST_OBJ_TYPE(
1346 : : mp_type_super,
1347 : : MP_QSTR_super,
1348 : : MP_TYPE_FLAG_NONE,
1349 : : make_new, super_make_new,
1350 : : print, super_print,
1351 : : attr, super_attr
1352 : : );
1353 : :
1354 : 100 : void mp_load_super_method(qstr attr, mp_obj_t *dest) {
1355 : 100 : mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]};
1356 : 100 : mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest);
1357 : 100 : }
1358 : :
1359 : : /******************************************************************************/
1360 : : // subclassing and built-ins specific to types
1361 : :
1362 : : // object and classinfo should be type objects
1363 : : // (but the function will fail gracefully if they are not)
1364 : 949119 : bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
1365 : 973749 : for (;;) {
1366 [ + + ]: 973749 : if (object == classinfo) {
1367 : : return true;
1368 : : }
1369 : :
1370 : : // not equivalent classes, keep searching base classes
1371 : :
1372 : : // object should always be a type object, but just return false if it's not
1373 [ + + + + ]: 511253 : if (!mp_obj_is_type(object, &mp_type_type)) {
1374 : : return false;
1375 : : }
1376 : :
1377 : 36230 : const mp_obj_type_t *self = MP_OBJ_TO_PTR(object);
1378 : :
1379 [ + + ]: 36230 : if (!MP_OBJ_TYPE_HAS_SLOT(self, parent)) {
1380 : : // type has no parents
1381 : : return false;
1382 : : #if MICROPY_MULTIPLE_INHERITANCE
1383 [ + + ]: 24634 : } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(self, parent))->type == &mp_type_tuple) {
1384 : : // get the base objects (they should be type objects)
1385 : 8 : const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(self, parent);
1386 : 8 : const mp_obj_t *item = parent_tuple->items;
1387 : 8 : const mp_obj_t *top = item + parent_tuple->len - 1;
1388 : :
1389 : : // iterate through the base objects
1390 [ + + ]: 12 : for (; item < top; ++item) {
1391 [ + + ]: 8 : if (mp_obj_is_subclass_fast(*item, classinfo)) {
1392 : : return true;
1393 : : }
1394 : : }
1395 : :
1396 : : // search last base (simple tail recursion elimination)
1397 : 4 : object = *item;
1398 : : #endif
1399 : : } else {
1400 : : // type has 1 parent
1401 : : object = MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(self, parent));
1402 : : }
1403 : : }
1404 : : }
1405 : :
1406 : 778 : static mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) {
1407 : 778 : size_t len;
1408 : 778 : mp_obj_t *items;
1409 [ + + + + ]: 778 : if (mp_obj_is_type(classinfo, &mp_type_type)) {
1410 : 564 : len = 1;
1411 : 564 : items = &classinfo;
1412 [ - + - + : 214 : } else if (mp_obj_is_type(classinfo, &mp_type_tuple)) {
- + - + +
+ + - ]
1413 : 202 : mp_obj_tuple_get(classinfo, &len, &items);
1414 : : } else {
1415 : 12 : mp_raise_TypeError(MP_ERROR_TEXT("issubclass() arg 2 must be a class or a tuple of classes"));
1416 : : }
1417 : :
1418 [ + + ]: 1160 : for (size_t i = 0; i < len; i++) {
1419 : : // We explicitly check for 'object' here since no-one explicitly derives from it
1420 [ + + + + ]: 930 : if (items[i] == MP_OBJ_FROM_PTR(&mp_type_object) || mp_obj_is_subclass_fast(object, items[i])) {
1421 : : return mp_const_true;
1422 : : }
1423 : : }
1424 : : return mp_const_false;
1425 : : }
1426 : :
1427 : 40 : static mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) {
1428 [ + + - + ]: 40 : if (!mp_obj_is_type(object, &mp_type_type)) {
1429 : 4 : mp_raise_TypeError(MP_ERROR_TEXT("issubclass() arg 1 must be a class"));
1430 : : }
1431 : 36 : return mp_obj_is_subclass(object, classinfo);
1432 : : }
1433 : :
1434 : : MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);
1435 : :
1436 : 674 : static mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
1437 : 674 : return mp_obj_is_subclass(MP_OBJ_FROM_PTR(mp_obj_get_type(object)), classinfo);
1438 : : }
1439 : :
1440 : : MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
1441 : :
1442 : 34 : mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type) {
1443 : 34 : const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
1444 : :
1445 [ + + ]: 34 : if (MP_OBJ_FROM_PTR(self_type) == native_type) {
1446 : : return self_in;
1447 [ + + ]: 18 : } else if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) {
1448 : : return MP_OBJ_NULL;
1449 : : } else {
1450 : 10 : mp_obj_instance_t *self = (mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in);
1451 : 10 : return self->subobj[0];
1452 : : }
1453 : : }
1454 : :
1455 : : /******************************************************************************/
1456 : : // staticmethod and classmethod types (probably should go in a different file)
1457 : :
1458 : 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) {
1459 [ + + - + ]: 100 : assert(self == &mp_type_staticmethod || self == &mp_type_classmethod);
1460 : :
1461 : 100 : mp_arg_check_num(n_args, n_kw, 1, 1, false);
1462 : :
1463 : 100 : mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t);
1464 : 100 : *o = (mp_obj_static_class_method_t) {{self}, args[0]};
1465 : 100 : return MP_OBJ_FROM_PTR(o);
1466 : : }
1467 : :
1468 : : MP_DEFINE_CONST_OBJ_TYPE(
1469 : : mp_type_staticmethod,
1470 : : MP_QSTR_staticmethod,
1471 : : MP_TYPE_FLAG_NONE,
1472 : : make_new, static_class_method_make_new
1473 : : );
1474 : :
1475 : : MP_DEFINE_CONST_OBJ_TYPE(
1476 : : mp_type_classmethod,
1477 : : MP_QSTR_classmethod,
1478 : : MP_TYPE_FLAG_NONE,
1479 : : make_new, static_class_method_make_new
1480 : : );
|