Port of MicroPython to the mbed platform. See micropython-repl for an interactive program.

Dependents:   micropython-repl

This a port of MicroPython to the mbed Classic platform.

This provides an interpreter running on the board's USB serial connection.

Getting Started

Import the micropython-repl program into your IDE workspace on developer.mbed.org. Compile and download to your board. Connect to the USB serial port in your usual manner. You should get a startup message similar to the following:

  MicroPython v1.7-155-gdddcdd8 on 2016-04-23; K64F with ARM
  Type "help()" for more information.
  >>>

Then you can start using micropython. For example:

  >>> from mbed import DigitalOut
  >>> from pins import LED1
  >>> led = DigitalOut(LED1)
  >>> led.write(1)

Requirements

You need approximately 100K of flash memory, so this will be no good for boards with smaller amounts of storage.

Caveats

This can be considered an alpha release of the port; things may not work; APIs may change in later releases. It is NOT an official part part the micropython project, so if anything doesn't work, blame me. If it does work, most of the credit is due to micropython.

  • Only a few of the mbed classes are available in micropython so far, and not all methods of those that are.
  • Only a few boards have their full range of pin names available; for others, only a few standard ones (USBTX, USBRX, LED1) are implemented.
  • The garbage collector is not yet implemented. The interpreter will gradually consume memory and then fail.
  • Exceptions from the mbed classes are not yet handled.
  • Asynchronous processing (e.g. events on inputs) is not supported.

Credits

  • Damien P. George and other contributors who created micropython.
  • Colin Hogben, author of this port.
Committer:
Colin Hogben
Date:
Wed Apr 27 22:11:29 2016 +0100
Revision:
10:33521d742af1
Parent:
0:5868e8752d44
Update README and version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pythontech 0:5868e8752d44 1 /*
pythontech 0:5868e8752d44 2 * This file is part of the Micro Python project, http://micropython.org/
pythontech 0:5868e8752d44 3 *
pythontech 0:5868e8752d44 4 * The MIT License (MIT)
pythontech 0:5868e8752d44 5 *
pythontech 0:5868e8752d44 6 * Copyright (c) 2013, 2014 Damien P. George
pythontech 0:5868e8752d44 7 *
pythontech 0:5868e8752d44 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
pythontech 0:5868e8752d44 9 * of this software and associated documentation files (the "Software"), to deal
pythontech 0:5868e8752d44 10 * in the Software without restriction, including without limitation the rights
pythontech 0:5868e8752d44 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
pythontech 0:5868e8752d44 12 * copies of the Software, and to permit persons to whom the Software is
pythontech 0:5868e8752d44 13 * furnished to do so, subject to the following conditions:
pythontech 0:5868e8752d44 14 *
pythontech 0:5868e8752d44 15 * The above copyright notice and this permission notice shall be included in
pythontech 0:5868e8752d44 16 * all copies or substantial portions of the Software.
pythontech 0:5868e8752d44 17 *
pythontech 0:5868e8752d44 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
pythontech 0:5868e8752d44 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
pythontech 0:5868e8752d44 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
pythontech 0:5868e8752d44 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
pythontech 0:5868e8752d44 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
pythontech 0:5868e8752d44 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
pythontech 0:5868e8752d44 24 * THE SOFTWARE.
pythontech 0:5868e8752d44 25 */
pythontech 0:5868e8752d44 26
pythontech 0:5868e8752d44 27 #include <assert.h>
pythontech 0:5868e8752d44 28 #include <stdio.h>
pythontech 0:5868e8752d44 29 #include <string.h>
pythontech 0:5868e8752d44 30
pythontech 0:5868e8752d44 31 #include "py/mpstate.h"
pythontech 0:5868e8752d44 32 #include "py/gc.h"
pythontech 0:5868e8752d44 33 #include "py/obj.h"
pythontech 0:5868e8752d44 34 #include "py/runtime.h"
pythontech 0:5868e8752d44 35
pythontech 0:5868e8752d44 36 #if MICROPY_ENABLE_GC
pythontech 0:5868e8752d44 37
pythontech 0:5868e8752d44 38 #if 0 // print debugging info
pythontech 0:5868e8752d44 39 #define DEBUG_PRINT (1)
pythontech 0:5868e8752d44 40 #define DEBUG_printf DEBUG_printf
pythontech 0:5868e8752d44 41 #else // don't print debugging info
pythontech 0:5868e8752d44 42 #define DEBUG_PRINT (0)
pythontech 0:5868e8752d44 43 #define DEBUG_printf(...) (void)0
pythontech 0:5868e8752d44 44 #endif
pythontech 0:5868e8752d44 45
pythontech 0:5868e8752d44 46 // make this 1 to dump the heap each time it changes
pythontech 0:5868e8752d44 47 #define EXTENSIVE_HEAP_PROFILING (0)
pythontech 0:5868e8752d44 48
pythontech 0:5868e8752d44 49 #define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)
pythontech 0:5868e8752d44 50 #define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
pythontech 0:5868e8752d44 51
pythontech 0:5868e8752d44 52 // ATB = allocation table byte
pythontech 0:5868e8752d44 53 // 0b00 = FREE -- free block
pythontech 0:5868e8752d44 54 // 0b01 = HEAD -- head of a chain of blocks
pythontech 0:5868e8752d44 55 // 0b10 = TAIL -- in the tail of a chain of blocks
pythontech 0:5868e8752d44 56 // 0b11 = MARK -- marked head block
pythontech 0:5868e8752d44 57
pythontech 0:5868e8752d44 58 #define AT_FREE (0)
pythontech 0:5868e8752d44 59 #define AT_HEAD (1)
pythontech 0:5868e8752d44 60 #define AT_TAIL (2)
pythontech 0:5868e8752d44 61 #define AT_MARK (3)
pythontech 0:5868e8752d44 62
pythontech 0:5868e8752d44 63 #define BLOCKS_PER_ATB (4)
pythontech 0:5868e8752d44 64 #define ATB_MASK_0 (0x03)
pythontech 0:5868e8752d44 65 #define ATB_MASK_1 (0x0c)
pythontech 0:5868e8752d44 66 #define ATB_MASK_2 (0x30)
pythontech 0:5868e8752d44 67 #define ATB_MASK_3 (0xc0)
pythontech 0:5868e8752d44 68
pythontech 0:5868e8752d44 69 #define ATB_0_IS_FREE(a) (((a) & ATB_MASK_0) == 0)
pythontech 0:5868e8752d44 70 #define ATB_1_IS_FREE(a) (((a) & ATB_MASK_1) == 0)
pythontech 0:5868e8752d44 71 #define ATB_2_IS_FREE(a) (((a) & ATB_MASK_2) == 0)
pythontech 0:5868e8752d44 72 #define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0)
pythontech 0:5868e8752d44 73
pythontech 0:5868e8752d44 74 #define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1)))
pythontech 0:5868e8752d44 75 #define ATB_GET_KIND(block) ((MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3)
pythontech 0:5868e8752d44 76 #define ATB_ANY_TO_FREE(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0)
pythontech 0:5868e8752d44 77 #define ATB_FREE_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0)
pythontech 0:5868e8752d44 78 #define ATB_FREE_TO_TAIL(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0)
pythontech 0:5868e8752d44 79 #define ATB_HEAD_TO_MARK(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
pythontech 0:5868e8752d44 80 #define ATB_MARK_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
pythontech 0:5868e8752d44 81
pythontech 0:5868e8752d44 82 #define BLOCK_FROM_PTR(ptr) (((byte*)(ptr) - MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK)
pythontech 0:5868e8752d44 83 #define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start)))
pythontech 0:5868e8752d44 84 #define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
pythontech 0:5868e8752d44 85
pythontech 0:5868e8752d44 86 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 87 // FTB = finaliser table byte
pythontech 0:5868e8752d44 88 // if set, then the corresponding block may have a finaliser
pythontech 0:5868e8752d44 89
pythontech 0:5868e8752d44 90 #define BLOCKS_PER_FTB (8)
pythontech 0:5868e8752d44 91
pythontech 0:5868e8752d44 92 #define FTB_GET(block) ((MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)
pythontech 0:5868e8752d44 93 #define FTB_SET(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)
pythontech 0:5868e8752d44 94 #define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
pythontech 0:5868e8752d44 95 #endif
pythontech 0:5868e8752d44 96
pythontech 0:5868e8752d44 97 // TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
pythontech 0:5868e8752d44 98 void gc_init(void *start, void *end) {
pythontech 0:5868e8752d44 99 // align end pointer on block boundary
pythontech 0:5868e8752d44 100 end = (void*)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1)));
pythontech 0:5868e8752d44 101 DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start);
pythontech 0:5868e8752d44 102
pythontech 0:5868e8752d44 103 // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
pythontech 0:5868e8752d44 104 // T = A + F + P
pythontech 0:5868e8752d44 105 // F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
pythontech 0:5868e8752d44 106 // P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
pythontech 0:5868e8752d44 107 // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
pythontech 0:5868e8752d44 108 size_t total_byte_len = (byte*)end - (byte*)start;
pythontech 0:5868e8752d44 109 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 110 MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
pythontech 0:5868e8752d44 111 #else
pythontech 0:5868e8752d44 112 MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
pythontech 0:5868e8752d44 113 #endif
pythontech 0:5868e8752d44 114
pythontech 0:5868e8752d44 115 MP_STATE_MEM(gc_alloc_table_start) = (byte*)start;
pythontech 0:5868e8752d44 116
pythontech 0:5868e8752d44 117 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 118 size_t gc_finaliser_table_byte_len = (MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
pythontech 0:5868e8752d44 119 MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len);
pythontech 0:5868e8752d44 120 #endif
pythontech 0:5868e8752d44 121
pythontech 0:5868e8752d44 122 size_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
pythontech 0:5868e8752d44 123 MP_STATE_MEM(gc_pool_start) = (byte*)end - gc_pool_block_len * BYTES_PER_BLOCK;
pythontech 0:5868e8752d44 124 MP_STATE_MEM(gc_pool_end) = end;
pythontech 0:5868e8752d44 125
pythontech 0:5868e8752d44 126 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 127 assert(MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len);
pythontech 0:5868e8752d44 128 #endif
pythontech 0:5868e8752d44 129
pythontech 0:5868e8752d44 130 // clear ATBs
pythontech 0:5868e8752d44 131 memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len));
pythontech 0:5868e8752d44 132
pythontech 0:5868e8752d44 133 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 134 // clear FTBs
pythontech 0:5868e8752d44 135 memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len);
pythontech 0:5868e8752d44 136 #endif
pythontech 0:5868e8752d44 137
pythontech 0:5868e8752d44 138 // set last free ATB index to start of heap
pythontech 0:5868e8752d44 139 MP_STATE_MEM(gc_last_free_atb_index) = 0;
pythontech 0:5868e8752d44 140
pythontech 0:5868e8752d44 141 // unlock the GC
pythontech 0:5868e8752d44 142 MP_STATE_MEM(gc_lock_depth) = 0;
pythontech 0:5868e8752d44 143
pythontech 0:5868e8752d44 144 // allow auto collection
pythontech 0:5868e8752d44 145 MP_STATE_MEM(gc_auto_collect_enabled) = 1;
pythontech 0:5868e8752d44 146
pythontech 0:5868e8752d44 147 DEBUG_printf("GC layout:\n");
pythontech 0:5868e8752d44 148 DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB);
pythontech 0:5868e8752d44 149 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 150 DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_finaliser_table_start), gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB);
pythontech 0:5868e8752d44 151 #endif
pythontech 0:5868e8752d44 152 DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len);
pythontech 0:5868e8752d44 153 }
pythontech 0:5868e8752d44 154
pythontech 0:5868e8752d44 155 void gc_lock(void) {
pythontech 0:5868e8752d44 156 MP_STATE_MEM(gc_lock_depth)++;
pythontech 0:5868e8752d44 157 }
pythontech 0:5868e8752d44 158
pythontech 0:5868e8752d44 159 void gc_unlock(void) {
pythontech 0:5868e8752d44 160 MP_STATE_MEM(gc_lock_depth)--;
pythontech 0:5868e8752d44 161 }
pythontech 0:5868e8752d44 162
pythontech 0:5868e8752d44 163 bool gc_is_locked(void) {
pythontech 0:5868e8752d44 164 return MP_STATE_MEM(gc_lock_depth) != 0;
pythontech 0:5868e8752d44 165 }
pythontech 0:5868e8752d44 166
pythontech 0:5868e8752d44 167 // ptr should be of type void*
pythontech 0:5868e8752d44 168 #define VERIFY_PTR(ptr) ( \
pythontech 0:5868e8752d44 169 ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
pythontech 0:5868e8752d44 170 && ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \
pythontech 0:5868e8752d44 171 && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \
pythontech 0:5868e8752d44 172 )
pythontech 0:5868e8752d44 173
pythontech 0:5868e8752d44 174 // ptr should be of type void*
pythontech 0:5868e8752d44 175 #define VERIFY_MARK_AND_PUSH(ptr) \
pythontech 0:5868e8752d44 176 do { \
pythontech 0:5868e8752d44 177 if (VERIFY_PTR(ptr)) { \
pythontech 0:5868e8752d44 178 size_t _block = BLOCK_FROM_PTR(ptr); \
pythontech 0:5868e8752d44 179 if (ATB_GET_KIND(_block) == AT_HEAD) { \
pythontech 0:5868e8752d44 180 /* an unmarked head, mark it, and push it on gc stack */ \
pythontech 0:5868e8752d44 181 DEBUG_printf("gc_mark(%p)\n", ptr); \
pythontech 0:5868e8752d44 182 ATB_HEAD_TO_MARK(_block); \
pythontech 0:5868e8752d44 183 if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \
pythontech 0:5868e8752d44 184 *MP_STATE_MEM(gc_sp)++ = _block; \
pythontech 0:5868e8752d44 185 } else { \
pythontech 0:5868e8752d44 186 MP_STATE_MEM(gc_stack_overflow) = 1; \
pythontech 0:5868e8752d44 187 } \
pythontech 0:5868e8752d44 188 } \
pythontech 0:5868e8752d44 189 } \
pythontech 0:5868e8752d44 190 } while (0)
pythontech 0:5868e8752d44 191
pythontech 0:5868e8752d44 192 STATIC void gc_drain_stack(void) {
pythontech 0:5868e8752d44 193 while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) {
pythontech 0:5868e8752d44 194 // pop the next block off the stack
pythontech 0:5868e8752d44 195 size_t block = *--MP_STATE_MEM(gc_sp);
pythontech 0:5868e8752d44 196
pythontech 0:5868e8752d44 197 // work out number of consecutive blocks in the chain starting with this one
pythontech 0:5868e8752d44 198 size_t n_blocks = 0;
pythontech 0:5868e8752d44 199 do {
pythontech 0:5868e8752d44 200 n_blocks += 1;
pythontech 0:5868e8752d44 201 } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
pythontech 0:5868e8752d44 202
pythontech 0:5868e8752d44 203 // check this block's children
pythontech 0:5868e8752d44 204 void **ptrs = (void**)PTR_FROM_BLOCK(block);
pythontech 0:5868e8752d44 205 for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) {
pythontech 0:5868e8752d44 206 void *ptr = *ptrs;
pythontech 0:5868e8752d44 207 VERIFY_MARK_AND_PUSH(ptr);
pythontech 0:5868e8752d44 208 }
pythontech 0:5868e8752d44 209 }
pythontech 0:5868e8752d44 210 }
pythontech 0:5868e8752d44 211
pythontech 0:5868e8752d44 212 STATIC void gc_deal_with_stack_overflow(void) {
pythontech 0:5868e8752d44 213 while (MP_STATE_MEM(gc_stack_overflow)) {
pythontech 0:5868e8752d44 214 MP_STATE_MEM(gc_stack_overflow) = 0;
pythontech 0:5868e8752d44 215 MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
pythontech 0:5868e8752d44 216
pythontech 0:5868e8752d44 217 // scan entire memory looking for blocks which have been marked but not their children
pythontech 0:5868e8752d44 218 for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
pythontech 0:5868e8752d44 219 // trace (again) if mark bit set
pythontech 0:5868e8752d44 220 if (ATB_GET_KIND(block) == AT_MARK) {
pythontech 0:5868e8752d44 221 *MP_STATE_MEM(gc_sp)++ = block;
pythontech 0:5868e8752d44 222 gc_drain_stack();
pythontech 0:5868e8752d44 223 }
pythontech 0:5868e8752d44 224 }
pythontech 0:5868e8752d44 225 }
pythontech 0:5868e8752d44 226 }
pythontech 0:5868e8752d44 227
pythontech 0:5868e8752d44 228 STATIC void gc_sweep(void) {
pythontech 0:5868e8752d44 229 #if MICROPY_PY_GC_COLLECT_RETVAL
pythontech 0:5868e8752d44 230 MP_STATE_MEM(gc_collected) = 0;
pythontech 0:5868e8752d44 231 #endif
pythontech 0:5868e8752d44 232 // free unmarked heads and their tails
pythontech 0:5868e8752d44 233 int free_tail = 0;
pythontech 0:5868e8752d44 234 for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
pythontech 0:5868e8752d44 235 switch (ATB_GET_KIND(block)) {
pythontech 0:5868e8752d44 236 case AT_HEAD:
pythontech 0:5868e8752d44 237 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 238 if (FTB_GET(block)) {
pythontech 0:5868e8752d44 239 mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block);
pythontech 0:5868e8752d44 240 if (obj->type != NULL) {
pythontech 0:5868e8752d44 241 // if the object has a type then see if it has a __del__ method
pythontech 0:5868e8752d44 242 mp_obj_t dest[2];
pythontech 0:5868e8752d44 243 mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest);
pythontech 0:5868e8752d44 244 if (dest[0] != MP_OBJ_NULL) {
pythontech 0:5868e8752d44 245 // load_method returned a method
pythontech 0:5868e8752d44 246 mp_call_method_n_kw(0, 0, dest);
pythontech 0:5868e8752d44 247 }
pythontech 0:5868e8752d44 248 }
pythontech 0:5868e8752d44 249 // clear finaliser flag
pythontech 0:5868e8752d44 250 FTB_CLEAR(block);
pythontech 0:5868e8752d44 251 }
pythontech 0:5868e8752d44 252 #endif
pythontech 0:5868e8752d44 253 free_tail = 1;
pythontech 0:5868e8752d44 254 DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block));
pythontech 0:5868e8752d44 255 #if MICROPY_PY_GC_COLLECT_RETVAL
pythontech 0:5868e8752d44 256 MP_STATE_MEM(gc_collected)++;
pythontech 0:5868e8752d44 257 #endif
pythontech 0:5868e8752d44 258 // fall through to free the head
pythontech 0:5868e8752d44 259
pythontech 0:5868e8752d44 260 case AT_TAIL:
pythontech 0:5868e8752d44 261 if (free_tail) {
pythontech 0:5868e8752d44 262 ATB_ANY_TO_FREE(block);
pythontech 0:5868e8752d44 263 }
pythontech 0:5868e8752d44 264 break;
pythontech 0:5868e8752d44 265
pythontech 0:5868e8752d44 266 case AT_MARK:
pythontech 0:5868e8752d44 267 ATB_MARK_TO_HEAD(block);
pythontech 0:5868e8752d44 268 free_tail = 0;
pythontech 0:5868e8752d44 269 break;
pythontech 0:5868e8752d44 270 }
pythontech 0:5868e8752d44 271 }
pythontech 0:5868e8752d44 272 }
pythontech 0:5868e8752d44 273
pythontech 0:5868e8752d44 274 void gc_collect_start(void) {
pythontech 0:5868e8752d44 275 gc_lock();
pythontech 0:5868e8752d44 276 MP_STATE_MEM(gc_stack_overflow) = 0;
pythontech 0:5868e8752d44 277 MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
pythontech 0:5868e8752d44 278 // Trace root pointers. This relies on the root pointers being organised
pythontech 0:5868e8752d44 279 // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals,
pythontech 0:5868e8752d44 280 // dict_globals, then the root pointer section of mp_state_vm.
pythontech 0:5868e8752d44 281 void **ptrs = (void**)(void*)&mp_state_ctx;
pythontech 0:5868e8752d44 282 gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(void*));
pythontech 0:5868e8752d44 283 }
pythontech 0:5868e8752d44 284
pythontech 0:5868e8752d44 285 void gc_collect_root(void **ptrs, size_t len) {
pythontech 0:5868e8752d44 286 for (size_t i = 0; i < len; i++) {
pythontech 0:5868e8752d44 287 void *ptr = ptrs[i];
pythontech 0:5868e8752d44 288 VERIFY_MARK_AND_PUSH(ptr);
pythontech 0:5868e8752d44 289 gc_drain_stack();
pythontech 0:5868e8752d44 290 }
pythontech 0:5868e8752d44 291 }
pythontech 0:5868e8752d44 292
pythontech 0:5868e8752d44 293 void gc_collect_end(void) {
pythontech 0:5868e8752d44 294 gc_deal_with_stack_overflow();
pythontech 0:5868e8752d44 295 gc_sweep();
pythontech 0:5868e8752d44 296 MP_STATE_MEM(gc_last_free_atb_index) = 0;
pythontech 0:5868e8752d44 297 gc_unlock();
pythontech 0:5868e8752d44 298 }
pythontech 0:5868e8752d44 299
pythontech 0:5868e8752d44 300 void gc_info(gc_info_t *info) {
pythontech 0:5868e8752d44 301 info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start);
pythontech 0:5868e8752d44 302 info->used = 0;
pythontech 0:5868e8752d44 303 info->free = 0;
pythontech 0:5868e8752d44 304 info->num_1block = 0;
pythontech 0:5868e8752d44 305 info->num_2block = 0;
pythontech 0:5868e8752d44 306 info->max_block = 0;
pythontech 0:5868e8752d44 307 for (size_t block = 0, len = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
pythontech 0:5868e8752d44 308 size_t kind = ATB_GET_KIND(block);
pythontech 0:5868e8752d44 309 if (kind == AT_FREE || kind == AT_HEAD) {
pythontech 0:5868e8752d44 310 if (len == 1) {
pythontech 0:5868e8752d44 311 info->num_1block += 1;
pythontech 0:5868e8752d44 312 } else if (len == 2) {
pythontech 0:5868e8752d44 313 info->num_2block += 1;
pythontech 0:5868e8752d44 314 }
pythontech 0:5868e8752d44 315 if (len > info->max_block) {
pythontech 0:5868e8752d44 316 info->max_block = len;
pythontech 0:5868e8752d44 317 }
pythontech 0:5868e8752d44 318 }
pythontech 0:5868e8752d44 319 switch (kind) {
pythontech 0:5868e8752d44 320 case AT_FREE:
pythontech 0:5868e8752d44 321 info->free += 1;
pythontech 0:5868e8752d44 322 len = 0;
pythontech 0:5868e8752d44 323 break;
pythontech 0:5868e8752d44 324
pythontech 0:5868e8752d44 325 case AT_HEAD:
pythontech 0:5868e8752d44 326 info->used += 1;
pythontech 0:5868e8752d44 327 len = 1;
pythontech 0:5868e8752d44 328 break;
pythontech 0:5868e8752d44 329
pythontech 0:5868e8752d44 330 case AT_TAIL:
pythontech 0:5868e8752d44 331 info->used += 1;
pythontech 0:5868e8752d44 332 len += 1;
pythontech 0:5868e8752d44 333 break;
pythontech 0:5868e8752d44 334
pythontech 0:5868e8752d44 335 case AT_MARK:
pythontech 0:5868e8752d44 336 // shouldn't happen
pythontech 0:5868e8752d44 337 break;
pythontech 0:5868e8752d44 338 }
pythontech 0:5868e8752d44 339 }
pythontech 0:5868e8752d44 340
pythontech 0:5868e8752d44 341 info->used *= BYTES_PER_BLOCK;
pythontech 0:5868e8752d44 342 info->free *= BYTES_PER_BLOCK;
pythontech 0:5868e8752d44 343 }
pythontech 0:5868e8752d44 344
pythontech 0:5868e8752d44 345 void *gc_alloc(size_t n_bytes, bool has_finaliser) {
pythontech 0:5868e8752d44 346 size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
pythontech 0:5868e8752d44 347 DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
pythontech 0:5868e8752d44 348
pythontech 0:5868e8752d44 349 // check if GC is locked
pythontech 0:5868e8752d44 350 if (MP_STATE_MEM(gc_lock_depth) > 0) {
pythontech 0:5868e8752d44 351 return NULL;
pythontech 0:5868e8752d44 352 }
pythontech 0:5868e8752d44 353
pythontech 0:5868e8752d44 354 // check for 0 allocation
pythontech 0:5868e8752d44 355 if (n_blocks == 0) {
pythontech 0:5868e8752d44 356 return NULL;
pythontech 0:5868e8752d44 357 }
pythontech 0:5868e8752d44 358
pythontech 0:5868e8752d44 359 size_t i;
pythontech 0:5868e8752d44 360 size_t end_block;
pythontech 0:5868e8752d44 361 size_t start_block;
pythontech 0:5868e8752d44 362 size_t n_free = 0;
pythontech 0:5868e8752d44 363 int collected = !MP_STATE_MEM(gc_auto_collect_enabled);
pythontech 0:5868e8752d44 364 for (;;) {
pythontech 0:5868e8752d44 365
pythontech 0:5868e8752d44 366 // look for a run of n_blocks available blocks
pythontech 0:5868e8752d44 367 for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) {
pythontech 0:5868e8752d44 368 byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
pythontech 0:5868e8752d44 369 if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
pythontech 0:5868e8752d44 370 if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
pythontech 0:5868e8752d44 371 if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }
pythontech 0:5868e8752d44 372 if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; }
pythontech 0:5868e8752d44 373 }
pythontech 0:5868e8752d44 374
pythontech 0:5868e8752d44 375 // nothing found!
pythontech 0:5868e8752d44 376 if (collected) {
pythontech 0:5868e8752d44 377 return NULL;
pythontech 0:5868e8752d44 378 }
pythontech 0:5868e8752d44 379 DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes);
pythontech 0:5868e8752d44 380 gc_collect();
pythontech 0:5868e8752d44 381 collected = 1;
pythontech 0:5868e8752d44 382 }
pythontech 0:5868e8752d44 383
pythontech 0:5868e8752d44 384 // found, ending at block i inclusive
pythontech 0:5868e8752d44 385 found:
pythontech 0:5868e8752d44 386 // get starting and end blocks, both inclusive
pythontech 0:5868e8752d44 387 end_block = i;
pythontech 0:5868e8752d44 388 start_block = i - n_free + 1;
pythontech 0:5868e8752d44 389
pythontech 0:5868e8752d44 390 // Set last free ATB index to block after last block we found, for start of
pythontech 0:5868e8752d44 391 // next scan. To reduce fragmentation, we only do this if we were looking
pythontech 0:5868e8752d44 392 // for a single free block, which guarantees that there are no free blocks
pythontech 0:5868e8752d44 393 // before this one. Also, whenever we free or shink a block we must check
pythontech 0:5868e8752d44 394 // if this index needs adjusting (see gc_realloc and gc_free).
pythontech 0:5868e8752d44 395 if (n_free == 1) {
pythontech 0:5868e8752d44 396 MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB;
pythontech 0:5868e8752d44 397 }
pythontech 0:5868e8752d44 398
pythontech 0:5868e8752d44 399 // mark first block as used head
pythontech 0:5868e8752d44 400 ATB_FREE_TO_HEAD(start_block);
pythontech 0:5868e8752d44 401
pythontech 0:5868e8752d44 402 // mark rest of blocks as used tail
pythontech 0:5868e8752d44 403 // TODO for a run of many blocks can make this more efficient
pythontech 0:5868e8752d44 404 for (size_t bl = start_block + 1; bl <= end_block; bl++) {
pythontech 0:5868e8752d44 405 ATB_FREE_TO_TAIL(bl);
pythontech 0:5868e8752d44 406 }
pythontech 0:5868e8752d44 407
pythontech 0:5868e8752d44 408 // get pointer to first block
pythontech 0:5868e8752d44 409 void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK);
pythontech 0:5868e8752d44 410 DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
pythontech 0:5868e8752d44 411
pythontech 0:5868e8752d44 412 // zero out the additional bytes of the newly allocated blocks
pythontech 0:5868e8752d44 413 // This is needed because the blocks may have previously held pointers
pythontech 0:5868e8752d44 414 // to the heap and will not be set to something else if the caller
pythontech 0:5868e8752d44 415 // doesn't actually use the entire block. As such they will continue
pythontech 0:5868e8752d44 416 // to point to the heap and may prevent other blocks from being reclaimed.
pythontech 0:5868e8752d44 417 memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
pythontech 0:5868e8752d44 418
pythontech 0:5868e8752d44 419 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 420 if (has_finaliser) {
pythontech 0:5868e8752d44 421 // clear type pointer in case it is never set
pythontech 0:5868e8752d44 422 ((mp_obj_base_t*)ret_ptr)->type = NULL;
pythontech 0:5868e8752d44 423 // set mp_obj flag only if it has a finaliser
pythontech 0:5868e8752d44 424 FTB_SET(start_block);
pythontech 0:5868e8752d44 425 }
pythontech 0:5868e8752d44 426 #else
pythontech 0:5868e8752d44 427 (void)has_finaliser;
pythontech 0:5868e8752d44 428 #endif
pythontech 0:5868e8752d44 429
pythontech 0:5868e8752d44 430 #if EXTENSIVE_HEAP_PROFILING
pythontech 0:5868e8752d44 431 gc_dump_alloc_table();
pythontech 0:5868e8752d44 432 #endif
pythontech 0:5868e8752d44 433
pythontech 0:5868e8752d44 434 return ret_ptr;
pythontech 0:5868e8752d44 435 }
pythontech 0:5868e8752d44 436
pythontech 0:5868e8752d44 437 /*
pythontech 0:5868e8752d44 438 void *gc_alloc(mp_uint_t n_bytes) {
pythontech 0:5868e8752d44 439 return _gc_alloc(n_bytes, false);
pythontech 0:5868e8752d44 440 }
pythontech 0:5868e8752d44 441
pythontech 0:5868e8752d44 442 void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
pythontech 0:5868e8752d44 443 return _gc_alloc(n_bytes, true);
pythontech 0:5868e8752d44 444 }
pythontech 0:5868e8752d44 445 */
pythontech 0:5868e8752d44 446
pythontech 0:5868e8752d44 447 // force the freeing of a piece of memory
pythontech 0:5868e8752d44 448 // TODO: freeing here does not call finaliser
pythontech 0:5868e8752d44 449 void gc_free(void *ptr) {
pythontech 0:5868e8752d44 450 if (MP_STATE_MEM(gc_lock_depth) > 0) {
pythontech 0:5868e8752d44 451 // TODO how to deal with this error?
pythontech 0:5868e8752d44 452 return;
pythontech 0:5868e8752d44 453 }
pythontech 0:5868e8752d44 454
pythontech 0:5868e8752d44 455 DEBUG_printf("gc_free(%p)\n", ptr);
pythontech 0:5868e8752d44 456
pythontech 0:5868e8752d44 457 if (VERIFY_PTR(ptr)) {
pythontech 0:5868e8752d44 458 size_t block = BLOCK_FROM_PTR(ptr);
pythontech 0:5868e8752d44 459 if (ATB_GET_KIND(block) == AT_HEAD) {
pythontech 0:5868e8752d44 460 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 461 FTB_CLEAR(block);
pythontech 0:5868e8752d44 462 #endif
pythontech 0:5868e8752d44 463 // set the last_free pointer to this block if it's earlier in the heap
pythontech 0:5868e8752d44 464 if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {
pythontech 0:5868e8752d44 465 MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB;
pythontech 0:5868e8752d44 466 }
pythontech 0:5868e8752d44 467
pythontech 0:5868e8752d44 468 // free head and all of its tail blocks
pythontech 0:5868e8752d44 469 do {
pythontech 0:5868e8752d44 470 ATB_ANY_TO_FREE(block);
pythontech 0:5868e8752d44 471 block += 1;
pythontech 0:5868e8752d44 472 } while (ATB_GET_KIND(block) == AT_TAIL);
pythontech 0:5868e8752d44 473
pythontech 0:5868e8752d44 474 #if EXTENSIVE_HEAP_PROFILING
pythontech 0:5868e8752d44 475 gc_dump_alloc_table();
pythontech 0:5868e8752d44 476 #endif
pythontech 0:5868e8752d44 477 } else {
pythontech 0:5868e8752d44 478 assert(!"bad free");
pythontech 0:5868e8752d44 479 }
pythontech 0:5868e8752d44 480 } else if (ptr != NULL) {
pythontech 0:5868e8752d44 481 assert(!"bad free");
pythontech 0:5868e8752d44 482 }
pythontech 0:5868e8752d44 483 }
pythontech 0:5868e8752d44 484
pythontech 0:5868e8752d44 485 size_t gc_nbytes(const void *ptr) {
pythontech 0:5868e8752d44 486 if (VERIFY_PTR(ptr)) {
pythontech 0:5868e8752d44 487 size_t block = BLOCK_FROM_PTR(ptr);
pythontech 0:5868e8752d44 488 if (ATB_GET_KIND(block) == AT_HEAD) {
pythontech 0:5868e8752d44 489 // work out number of consecutive blocks in the chain starting with this on
pythontech 0:5868e8752d44 490 size_t n_blocks = 0;
pythontech 0:5868e8752d44 491 do {
pythontech 0:5868e8752d44 492 n_blocks += 1;
pythontech 0:5868e8752d44 493 } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
pythontech 0:5868e8752d44 494 return n_blocks * BYTES_PER_BLOCK;
pythontech 0:5868e8752d44 495 }
pythontech 0:5868e8752d44 496 }
pythontech 0:5868e8752d44 497
pythontech 0:5868e8752d44 498 // invalid pointer
pythontech 0:5868e8752d44 499 return 0;
pythontech 0:5868e8752d44 500 }
pythontech 0:5868e8752d44 501
pythontech 0:5868e8752d44 502 #if 0
pythontech 0:5868e8752d44 503 // old, simple realloc that didn't expand memory in place
pythontech 0:5868e8752d44 504 void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
pythontech 0:5868e8752d44 505 mp_uint_t n_existing = gc_nbytes(ptr);
pythontech 0:5868e8752d44 506 if (n_bytes <= n_existing) {
pythontech 0:5868e8752d44 507 return ptr;
pythontech 0:5868e8752d44 508 } else {
pythontech 0:5868e8752d44 509 bool has_finaliser;
pythontech 0:5868e8752d44 510 if (ptr == NULL) {
pythontech 0:5868e8752d44 511 has_finaliser = false;
pythontech 0:5868e8752d44 512 } else {
pythontech 0:5868e8752d44 513 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 514 has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));
pythontech 0:5868e8752d44 515 #else
pythontech 0:5868e8752d44 516 has_finaliser = false;
pythontech 0:5868e8752d44 517 #endif
pythontech 0:5868e8752d44 518 }
pythontech 0:5868e8752d44 519 void *ptr2 = gc_alloc(n_bytes, has_finaliser);
pythontech 0:5868e8752d44 520 if (ptr2 == NULL) {
pythontech 0:5868e8752d44 521 return ptr2;
pythontech 0:5868e8752d44 522 }
pythontech 0:5868e8752d44 523 memcpy(ptr2, ptr, n_existing);
pythontech 0:5868e8752d44 524 gc_free(ptr);
pythontech 0:5868e8752d44 525 return ptr2;
pythontech 0:5868e8752d44 526 }
pythontech 0:5868e8752d44 527 }
pythontech 0:5868e8752d44 528
pythontech 0:5868e8752d44 529 #else // Alternative gc_realloc impl
pythontech 0:5868e8752d44 530
pythontech 0:5868e8752d44 531 void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
pythontech 0:5868e8752d44 532 if (MP_STATE_MEM(gc_lock_depth) > 0) {
pythontech 0:5868e8752d44 533 return NULL;
pythontech 0:5868e8752d44 534 }
pythontech 0:5868e8752d44 535
pythontech 0:5868e8752d44 536 // check for pure allocation
pythontech 0:5868e8752d44 537 if (ptr_in == NULL) {
pythontech 0:5868e8752d44 538 return gc_alloc(n_bytes, false);
pythontech 0:5868e8752d44 539 }
pythontech 0:5868e8752d44 540
pythontech 0:5868e8752d44 541 // check for pure free
pythontech 0:5868e8752d44 542 if (n_bytes == 0) {
pythontech 0:5868e8752d44 543 gc_free(ptr_in);
pythontech 0:5868e8752d44 544 return NULL;
pythontech 0:5868e8752d44 545 }
pythontech 0:5868e8752d44 546
pythontech 0:5868e8752d44 547 void *ptr = ptr_in;
pythontech 0:5868e8752d44 548
pythontech 0:5868e8752d44 549 // sanity check the ptr
pythontech 0:5868e8752d44 550 if (!VERIFY_PTR(ptr)) {
pythontech 0:5868e8752d44 551 return NULL;
pythontech 0:5868e8752d44 552 }
pythontech 0:5868e8752d44 553
pythontech 0:5868e8752d44 554 // get first block
pythontech 0:5868e8752d44 555 size_t block = BLOCK_FROM_PTR(ptr);
pythontech 0:5868e8752d44 556
pythontech 0:5868e8752d44 557 // sanity check the ptr is pointing to the head of a block
pythontech 0:5868e8752d44 558 if (ATB_GET_KIND(block) != AT_HEAD) {
pythontech 0:5868e8752d44 559 return NULL;
pythontech 0:5868e8752d44 560 }
pythontech 0:5868e8752d44 561
pythontech 0:5868e8752d44 562 // compute number of new blocks that are requested
pythontech 0:5868e8752d44 563 size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
pythontech 0:5868e8752d44 564
pythontech 0:5868e8752d44 565 // Get the total number of consecutive blocks that are already allocated to
pythontech 0:5868e8752d44 566 // this chunk of memory, and then count the number of free blocks following
pythontech 0:5868e8752d44 567 // it. Stop if we reach the end of the heap, or if we find enough extra
pythontech 0:5868e8752d44 568 // free blocks to satisfy the realloc. Note that we need to compute the
pythontech 0:5868e8752d44 569 // total size of the existing memory chunk so we can correctly and
pythontech 0:5868e8752d44 570 // efficiently shrink it (see below for shrinking code).
pythontech 0:5868e8752d44 571 size_t n_free = 0;
pythontech 0:5868e8752d44 572 size_t n_blocks = 1; // counting HEAD block
pythontech 0:5868e8752d44 573 size_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
pythontech 0:5868e8752d44 574 for (size_t bl = block + n_blocks; bl < max_block; bl++) {
pythontech 0:5868e8752d44 575 byte block_type = ATB_GET_KIND(bl);
pythontech 0:5868e8752d44 576 if (block_type == AT_TAIL) {
pythontech 0:5868e8752d44 577 n_blocks++;
pythontech 0:5868e8752d44 578 continue;
pythontech 0:5868e8752d44 579 }
pythontech 0:5868e8752d44 580 if (block_type == AT_FREE) {
pythontech 0:5868e8752d44 581 n_free++;
pythontech 0:5868e8752d44 582 if (n_blocks + n_free >= new_blocks) {
pythontech 0:5868e8752d44 583 // stop as soon as we find enough blocks for n_bytes
pythontech 0:5868e8752d44 584 break;
pythontech 0:5868e8752d44 585 }
pythontech 0:5868e8752d44 586 continue;
pythontech 0:5868e8752d44 587 }
pythontech 0:5868e8752d44 588 break;
pythontech 0:5868e8752d44 589 }
pythontech 0:5868e8752d44 590
pythontech 0:5868e8752d44 591 // return original ptr if it already has the requested number of blocks
pythontech 0:5868e8752d44 592 if (new_blocks == n_blocks) {
pythontech 0:5868e8752d44 593 return ptr_in;
pythontech 0:5868e8752d44 594 }
pythontech 0:5868e8752d44 595
pythontech 0:5868e8752d44 596 // check if we can shrink the allocated area
pythontech 0:5868e8752d44 597 if (new_blocks < n_blocks) {
pythontech 0:5868e8752d44 598 // free unneeded tail blocks
pythontech 0:5868e8752d44 599 for (size_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) {
pythontech 0:5868e8752d44 600 ATB_ANY_TO_FREE(bl);
pythontech 0:5868e8752d44 601 }
pythontech 0:5868e8752d44 602
pythontech 0:5868e8752d44 603 // set the last_free pointer to end of this block if it's earlier in the heap
pythontech 0:5868e8752d44 604 if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {
pythontech 0:5868e8752d44 605 MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
pythontech 0:5868e8752d44 606 }
pythontech 0:5868e8752d44 607
pythontech 0:5868e8752d44 608 #if EXTENSIVE_HEAP_PROFILING
pythontech 0:5868e8752d44 609 gc_dump_alloc_table();
pythontech 0:5868e8752d44 610 #endif
pythontech 0:5868e8752d44 611
pythontech 0:5868e8752d44 612 return ptr_in;
pythontech 0:5868e8752d44 613 }
pythontech 0:5868e8752d44 614
pythontech 0:5868e8752d44 615 // check if we can expand in place
pythontech 0:5868e8752d44 616 if (new_blocks <= n_blocks + n_free) {
pythontech 0:5868e8752d44 617 // mark few more blocks as used tail
pythontech 0:5868e8752d44 618 for (size_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
pythontech 0:5868e8752d44 619 assert(ATB_GET_KIND(bl) == AT_FREE);
pythontech 0:5868e8752d44 620 ATB_FREE_TO_TAIL(bl);
pythontech 0:5868e8752d44 621 }
pythontech 0:5868e8752d44 622
pythontech 0:5868e8752d44 623 // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
pythontech 0:5868e8752d44 624 memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
pythontech 0:5868e8752d44 625
pythontech 0:5868e8752d44 626 #if EXTENSIVE_HEAP_PROFILING
pythontech 0:5868e8752d44 627 gc_dump_alloc_table();
pythontech 0:5868e8752d44 628 #endif
pythontech 0:5868e8752d44 629
pythontech 0:5868e8752d44 630 return ptr_in;
pythontech 0:5868e8752d44 631 }
pythontech 0:5868e8752d44 632
pythontech 0:5868e8752d44 633 if (!allow_move) {
pythontech 0:5868e8752d44 634 // not allowed to move memory block so return failure
pythontech 0:5868e8752d44 635 return NULL;
pythontech 0:5868e8752d44 636 }
pythontech 0:5868e8752d44 637
pythontech 0:5868e8752d44 638 // can't resize inplace; try to find a new contiguous chain
pythontech 0:5868e8752d44 639 void *ptr_out = gc_alloc(n_bytes,
pythontech 0:5868e8752d44 640 #if MICROPY_ENABLE_FINALISER
pythontech 0:5868e8752d44 641 FTB_GET(block)
pythontech 0:5868e8752d44 642 #else
pythontech 0:5868e8752d44 643 false
pythontech 0:5868e8752d44 644 #endif
pythontech 0:5868e8752d44 645 );
pythontech 0:5868e8752d44 646
pythontech 0:5868e8752d44 647 // check that the alloc succeeded
pythontech 0:5868e8752d44 648 if (ptr_out == NULL) {
pythontech 0:5868e8752d44 649 return NULL;
pythontech 0:5868e8752d44 650 }
pythontech 0:5868e8752d44 651
pythontech 0:5868e8752d44 652 DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out);
pythontech 0:5868e8752d44 653 memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
pythontech 0:5868e8752d44 654 gc_free(ptr_in);
pythontech 0:5868e8752d44 655 return ptr_out;
pythontech 0:5868e8752d44 656 }
pythontech 0:5868e8752d44 657 #endif // Alternative gc_realloc impl
pythontech 0:5868e8752d44 658
pythontech 0:5868e8752d44 659 void gc_dump_info(void) {
pythontech 0:5868e8752d44 660 gc_info_t info;
pythontech 0:5868e8752d44 661 gc_info(&info);
pythontech 0:5868e8752d44 662 mp_printf(&mp_plat_print, "GC: total: %u, used: %u, free: %u\n",
pythontech 0:5868e8752d44 663 (uint)info.total, (uint)info.used, (uint)info.free);
pythontech 0:5868e8752d44 664 mp_printf(&mp_plat_print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u\n",
pythontech 0:5868e8752d44 665 (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block);
pythontech 0:5868e8752d44 666 }
pythontech 0:5868e8752d44 667
pythontech 0:5868e8752d44 668 void gc_dump_alloc_table(void) {
pythontech 0:5868e8752d44 669 static const size_t DUMP_BYTES_PER_LINE = 64;
pythontech 0:5868e8752d44 670 #if !EXTENSIVE_HEAP_PROFILING
pythontech 0:5868e8752d44 671 // When comparing heap output we don't want to print the starting
pythontech 0:5868e8752d44 672 // pointer of the heap because it changes from run to run.
pythontech 0:5868e8752d44 673 mp_printf(&mp_plat_print, "GC memory layout; from %p:", MP_STATE_MEM(gc_pool_start));
pythontech 0:5868e8752d44 674 #endif
pythontech 0:5868e8752d44 675 for (size_t bl = 0; bl < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; bl++) {
pythontech 0:5868e8752d44 676 if (bl % DUMP_BYTES_PER_LINE == 0) {
pythontech 0:5868e8752d44 677 // a new line of blocks
pythontech 0:5868e8752d44 678 {
pythontech 0:5868e8752d44 679 // check if this line contains only free blocks
pythontech 0:5868e8752d44 680 size_t bl2 = bl;
pythontech 0:5868e8752d44 681 while (bl2 < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
pythontech 0:5868e8752d44 682 bl2++;
pythontech 0:5868e8752d44 683 }
pythontech 0:5868e8752d44 684 if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) {
pythontech 0:5868e8752d44 685 // there are at least 2 lines containing only free blocks, so abbreviate their printing
pythontech 0:5868e8752d44 686 mp_printf(&mp_plat_print, "\n (%u lines all free)", (uint)(bl2 - bl) / DUMP_BYTES_PER_LINE);
pythontech 0:5868e8752d44 687 bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1));
pythontech 0:5868e8752d44 688 if (bl >= MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB) {
pythontech 0:5868e8752d44 689 // got to end of heap
pythontech 0:5868e8752d44 690 break;
pythontech 0:5868e8752d44 691 }
pythontech 0:5868e8752d44 692 }
pythontech 0:5868e8752d44 693 }
pythontech 0:5868e8752d44 694 // print header for new line of blocks
pythontech 0:5868e8752d44 695 // (the cast to uint32_t is for 16-bit ports)
pythontech 0:5868e8752d44 696 #if EXTENSIVE_HEAP_PROFILING
pythontech 0:5868e8752d44 697 mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff));
pythontech 0:5868e8752d44 698 #else
pythontech 0:5868e8752d44 699 mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff));
pythontech 0:5868e8752d44 700 #endif
pythontech 0:5868e8752d44 701 }
pythontech 0:5868e8752d44 702 int c = ' ';
pythontech 0:5868e8752d44 703 switch (ATB_GET_KIND(bl)) {
pythontech 0:5868e8752d44 704 case AT_FREE: c = '.'; break;
pythontech 0:5868e8752d44 705 /* this prints out if the object is reachable from BSS or STACK (for unix only)
pythontech 0:5868e8752d44 706 case AT_HEAD: {
pythontech 0:5868e8752d44 707 c = 'h';
pythontech 0:5868e8752d44 708 void **ptrs = (void**)(void*)&mp_state_ctx;
pythontech 0:5868e8752d44 709 mp_uint_t len = offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t);
pythontech 0:5868e8752d44 710 for (mp_uint_t i = 0; i < len; i++) {
pythontech 0:5868e8752d44 711 mp_uint_t ptr = (mp_uint_t)ptrs[i];
pythontech 0:5868e8752d44 712 if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
pythontech 0:5868e8752d44 713 c = 'B';
pythontech 0:5868e8752d44 714 break;
pythontech 0:5868e8752d44 715 }
pythontech 0:5868e8752d44 716 }
pythontech 0:5868e8752d44 717 if (c == 'h') {
pythontech 0:5868e8752d44 718 ptrs = (void**)&c;
pythontech 0:5868e8752d44 719 len = ((mp_uint_t)MP_STATE_VM(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t);
pythontech 0:5868e8752d44 720 for (mp_uint_t i = 0; i < len; i++) {
pythontech 0:5868e8752d44 721 mp_uint_t ptr = (mp_uint_t)ptrs[i];
pythontech 0:5868e8752d44 722 if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
pythontech 0:5868e8752d44 723 c = 'S';
pythontech 0:5868e8752d44 724 break;
pythontech 0:5868e8752d44 725 }
pythontech 0:5868e8752d44 726 }
pythontech 0:5868e8752d44 727 }
pythontech 0:5868e8752d44 728 break;
pythontech 0:5868e8752d44 729 }
pythontech 0:5868e8752d44 730 */
pythontech 0:5868e8752d44 731 /* this prints the uPy object type of the head block */
pythontech 0:5868e8752d44 732 case AT_HEAD: {
pythontech 0:5868e8752d44 733 void **ptr = (void**)(MP_STATE_MEM(gc_pool_start) + bl * BYTES_PER_BLOCK);
pythontech 0:5868e8752d44 734 if (*ptr == &mp_type_tuple) { c = 'T'; }
pythontech 0:5868e8752d44 735 else if (*ptr == &mp_type_list) { c = 'L'; }
pythontech 0:5868e8752d44 736 else if (*ptr == &mp_type_dict) { c = 'D'; }
pythontech 0:5868e8752d44 737 #if MICROPY_PY_BUILTINS_FLOAT
pythontech 0:5868e8752d44 738 else if (*ptr == &mp_type_float) { c = 'F'; }
pythontech 0:5868e8752d44 739 #endif
pythontech 0:5868e8752d44 740 else if (*ptr == &mp_type_fun_bc) { c = 'B'; }
pythontech 0:5868e8752d44 741 else if (*ptr == &mp_type_module) { c = 'M'; }
pythontech 0:5868e8752d44 742 else {
pythontech 0:5868e8752d44 743 c = 'h';
pythontech 0:5868e8752d44 744 #if 0
pythontech 0:5868e8752d44 745 // This code prints "Q" for qstr-pool data, and "q" for qstr-str
pythontech 0:5868e8752d44 746 // data. It can be useful to see how qstrs are being allocated,
pythontech 0:5868e8752d44 747 // but is disabled by default because it is very slow.
pythontech 0:5868e8752d44 748 for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) {
pythontech 0:5868e8752d44 749 if ((qstr_pool_t*)ptr == pool) {
pythontech 0:5868e8752d44 750 c = 'Q';
pythontech 0:5868e8752d44 751 break;
pythontech 0:5868e8752d44 752 }
pythontech 0:5868e8752d44 753 for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
pythontech 0:5868e8752d44 754 if ((const byte*)ptr == *q) {
pythontech 0:5868e8752d44 755 c = 'q';
pythontech 0:5868e8752d44 756 break;
pythontech 0:5868e8752d44 757 }
pythontech 0:5868e8752d44 758 }
pythontech 0:5868e8752d44 759 }
pythontech 0:5868e8752d44 760 #endif
pythontech 0:5868e8752d44 761 }
pythontech 0:5868e8752d44 762 break;
pythontech 0:5868e8752d44 763 }
pythontech 0:5868e8752d44 764 case AT_TAIL: c = 't'; break;
pythontech 0:5868e8752d44 765 case AT_MARK: c = 'm'; break;
pythontech 0:5868e8752d44 766 }
pythontech 0:5868e8752d44 767 mp_printf(&mp_plat_print, "%c", c);
pythontech 0:5868e8752d44 768 }
pythontech 0:5868e8752d44 769 mp_print_str(&mp_plat_print, "\n");
pythontech 0:5868e8752d44 770 }
pythontech 0:5868e8752d44 771
pythontech 0:5868e8752d44 772 #if DEBUG_PRINT
pythontech 0:5868e8752d44 773 void gc_test(void) {
pythontech 0:5868e8752d44 774 mp_uint_t len = 500;
pythontech 0:5868e8752d44 775 mp_uint_t *heap = malloc(len);
pythontech 0:5868e8752d44 776 gc_init(heap, heap + len / sizeof(mp_uint_t));
pythontech 0:5868e8752d44 777 void *ptrs[100];
pythontech 0:5868e8752d44 778 {
pythontech 0:5868e8752d44 779 mp_uint_t **p = gc_alloc(16, false);
pythontech 0:5868e8752d44 780 p[0] = gc_alloc(64, false);
pythontech 0:5868e8752d44 781 p[1] = gc_alloc(1, false);
pythontech 0:5868e8752d44 782 p[2] = gc_alloc(1, false);
pythontech 0:5868e8752d44 783 p[3] = gc_alloc(1, false);
pythontech 0:5868e8752d44 784 mp_uint_t ***p2 = gc_alloc(16, false);
pythontech 0:5868e8752d44 785 p2[0] = p;
pythontech 0:5868e8752d44 786 p2[1] = p;
pythontech 0:5868e8752d44 787 ptrs[0] = p2;
pythontech 0:5868e8752d44 788 }
pythontech 0:5868e8752d44 789 for (int i = 0; i < 25; i+=2) {
pythontech 0:5868e8752d44 790 mp_uint_t *p = gc_alloc(i, false);
pythontech 0:5868e8752d44 791 printf("p=%p\n", p);
pythontech 0:5868e8752d44 792 if (i & 3) {
pythontech 0:5868e8752d44 793 //ptrs[i] = p;
pythontech 0:5868e8752d44 794 }
pythontech 0:5868e8752d44 795 }
pythontech 0:5868e8752d44 796
pythontech 0:5868e8752d44 797 printf("Before GC:\n");
pythontech 0:5868e8752d44 798 gc_dump_alloc_table();
pythontech 0:5868e8752d44 799 printf("Starting GC...\n");
pythontech 0:5868e8752d44 800 gc_collect_start();
pythontech 0:5868e8752d44 801 gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void*));
pythontech 0:5868e8752d44 802 gc_collect_end();
pythontech 0:5868e8752d44 803 printf("After GC:\n");
pythontech 0:5868e8752d44 804 gc_dump_alloc_table();
pythontech 0:5868e8752d44 805 }
pythontech 0:5868e8752d44 806 #endif
pythontech 0:5868e8752d44 807
pythontech 0:5868e8752d44 808 #endif // MICROPY_ENABLE_GC