293 lines
9.9 KiB
C
293 lines
9.9 KiB
C
/*
|
|
* 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 <stdint.h>
|
|
|
|
#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);
|
|
}
|