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