/* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2016 Scott Shawcroft * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "py/bc.h" #include "py/binary.h" #include "py/gc.h" #include "py/obj.h" #include "py/objarray.h" #include "py/objfun.h" #include "py/objint.h" #include "py/objstr.h" #include "py/objtype.h" #include "py/runtime.h" #include "shared-bindings/uheap/__init__.h" #define VERIFY_PTR(ptr) ( \ (void *) ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \ && (void *) ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \ ) static void indent(uint8_t levels) { for (int i = 0; i < levels; i++) { mp_printf(&mp_plat_print, " "); } } static uint32_t object_size(uint8_t indent_level, mp_obj_t obj); static uint32_t int_size(uint8_t indent_level, mp_obj_t obj) { if (MP_OBJ_IS_SMALL_INT(obj)) { return 0; } if (!VERIFY_PTR(obj)) { return 0; } #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ mp_obj_int_t* i = MP_OBJ_TO_PTR(obj); return gc_nbytes(obj) + gc_nbytes(i->mpz.dig); #else return gc_nbytes(obj); #endif } static uint32_t string_size(uint8_t indent_level, mp_obj_t obj) { if (MP_OBJ_IS_QSTR(obj)) { qstr qs = MP_OBJ_QSTR_VALUE(obj); const char* s = qstr_str(qs); if (!VERIFY_PTR(s)) { return 0; } indent(indent_level); mp_printf(&mp_plat_print, "%s\n", s); return 0; } else { // MP_OBJ_IS_TYPE(o, &mp_type_str) mp_obj_str_t* s = MP_OBJ_TO_PTR(obj); return gc_nbytes(s) + gc_nbytes(s->data); } } static uint32_t map_size(uint8_t indent_level, const mp_map_t *map) { uint32_t total_size = gc_nbytes(map->table); for (int i = 0; i < map->used; i++) { uint32_t this_size = 0; indent(indent_level); if (map->table[i].key != NULL) { mp_print_str(&mp_plat_print, "key: "); mp_obj_print_helper(&mp_plat_print, map->table[i].key, PRINT_STR); mp_print_str(&mp_plat_print, "\n"); } else { mp_print_str(&mp_plat_print, "null key\n"); } this_size += object_size(indent_level + 1, map->table[i].key); this_size += object_size(indent_level + 1, map->table[i].value); indent(indent_level); mp_printf(&mp_plat_print, "Entry size: %u\n\n", this_size); total_size += this_size; } return total_size; } static uint32_t dict_size(uint8_t indent_level, mp_obj_dict_t *dict) { uint32_t total_size = gc_nbytes(dict); indent(indent_level); mp_printf(&mp_plat_print, "Dictionary @%x\n", dict); total_size += map_size(indent_level, &dict->map); return total_size; } static uint32_t function_size(uint8_t indent_level, mp_obj_t obj) { //indent(indent_level); //mp_print_str(&mp_plat_print, "function\n"); if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_0)) { return 0; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_1)) { return 0; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_2)) { return 0; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_3)) { return 0; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_var)) { return 0; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_bc)) { mp_obj_fun_bc_t* fn = MP_OBJ_TO_PTR(obj); uint32_t total_size = gc_nbytes(fn) + gc_nbytes(fn->bytecode) + gc_nbytes(fn->const_table); #if MICROPY_DEBUG_PRINTERS mp_printf(&mp_plat_print, "BYTECODE START\n"); mp_bytecode_print(fn, fn->bytecode, gc_nbytes(fn->bytecode), fn->const_table); mp_printf(&mp_plat_print, "BYTECODE END\n"); #endif return total_size; #if MICROPY_EMIT_NATIVE } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_native)) { return 0; #endif #if MICROPY_EMIT_NATIVE } else if (MP_OBJ_IS_TYPE(obj, &mp_obj_fun_viper_t)) { return 0; #endif #if MICROPY_EMIT_THUMB } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_asm)) { return 0; #endif } return 0; } static uint32_t array_size(uint8_t indent_level, mp_obj_array_t *array) { uint32_t total_size = gc_nbytes(array); uint32_t item_size = gc_nbytes(array->items); total_size += item_size; indent(indent_level); mp_printf(&mp_plat_print, "Array of size: %u\n\n", item_size); return total_size; } static uint32_t memoryview_size(uint8_t indent_level, mp_obj_array_t *array) { uint32_t total_size = gc_nbytes(array); indent(indent_level); mp_printf(&mp_plat_print, "memoryview\n"); return total_size; } static uint32_t type_size(uint8_t indent_level, mp_obj_type_t *type) { uint32_t total_size = gc_nbytes(type); // mp_obj_base_t base; // qstr name; //total_size += string_size(indent_level, MP_OBJ_TO_PTR(type->name)); // mp_print_fun_t print; // mp_make_new_fun_t make_new; // to make an instance of the type // // mp_call_fun_t call; // mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported // mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported // // // implements load, store and delete attribute // // // // dest[0] = MP_OBJ_NULL means load // // return: for fail, do nothing // // for attr, dest[0] = value // // for method, dest[0] = method, dest[1] = self // // // // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete // // dest[0,1] = {MP_OBJ_SENTINEL, object} means store // // return: for fail, do nothing // // for success set dest[0] = MP_OBJ_NULL // mp_attr_fun_t attr; // // mp_subscr_fun_t subscr; // implements load, store, delete subscripting // // value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store // // can return MP_OBJ_NULL if op not supported // // mp_fun_1_t getiter; // corresponds to __iter__ special method // mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args) // // mp_buffer_p_t buffer_p; // // One of disjoint protocols (interfaces), like mp_stream_p_t, etc. // const void *protocol; // // // these are for dynamically created types (classes) // struct _mp_obj_tuple_t *bases_tuple; // struct _mp_obj_dict_t *locals_dict; if (type->locals_dict != NULL) { total_size += dict_size(indent_level, type->locals_dict); } indent(indent_level); mp_printf(&mp_plat_print, "TYPE\n"); return total_size; } static uint32_t instance_size(uint8_t indent_level, mp_obj_instance_t *instance) { uint32_t total_size = gc_nbytes(instance); total_size += map_size(indent_level, &instance->members); return total_size; } static uint32_t module_size(uint8_t indent_level, mp_obj_module_t *module) { uint32_t total_size = gc_nbytes(module); indent(indent_level); mp_printf(&mp_plat_print, ".globals\n"); total_size += dict_size(indent_level + 1, module->globals); indent(indent_level); mp_printf(&mp_plat_print, "Module size: %u\n", total_size); return total_size; } static uint32_t object_size(uint8_t indent_level, mp_obj_t obj) { if (obj == NULL) { return 0; } if (MP_OBJ_IS_INT(obj)) { return int_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (MP_OBJ_IS_STR(obj)) { return string_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (MP_OBJ_IS_FUN(obj)) { return function_size(indent_level, MP_OBJ_TO_PTR(obj)); } if (!VERIFY_PTR(obj)) { //indent(indent_level); //mp_printf(&mp_plat_print, "In ROM\n"); return 0; } mp_obj_t type = MP_OBJ_FROM_PTR(mp_obj_get_type(obj)); if (type == &mp_type_module) { return module_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (type == &mp_type_dict) { return dict_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (type == &mp_type_type) { return type_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (type == &mp_type_bytearray || type == &mp_type_array) { return array_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (type == &mp_type_memoryview) { return memoryview_size(indent_level, MP_OBJ_TO_PTR(obj)); } else if (MP_OBJ_IS_OBJ(obj) && VERIFY_PTR(type)) { return instance_size(indent_level, MP_OBJ_TO_PTR(obj)); } indent(indent_level); mp_printf(&mp_plat_print, "unknown type %x\n", type); return 0; } uint32_t shared_module_uheap_info(mp_obj_t obj) { if (!VERIFY_PTR(obj)) { mp_printf(&mp_plat_print, "Object not on heap.\n"); return 0; } return object_size(0, obj); }