blob: f48cb8da4fd47d4b3aa6d092bd1b7eba921648b7 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Damien429d7192013-10-04 19:53:11 +010027#include <stdio.h>
28#include <stdlib.h>
Paul Sokolovsky58ff93b2014-02-10 18:37:11 +020029#include <string.h>
Damien429d7192013-10-04 19:53:11 +010030
Damien George51dfcb42015-01-01 20:27:54 +000031#include "py/mpconfig.h"
32#include "py/misc.h"
Damien Georgeb4b10fd2015-01-01 23:30:53 +000033#include "py/mpstate.h"
Damien429d7192013-10-04 19:53:11 +010034
Damien George2d15c122014-01-29 20:33:20 +000035#if 0 // print debugging info
Paul Sokolovsky44739e22014-02-16 18:11:42 +020036#define DEBUG_printf DEBUG_printf
Damien George2d15c122014-01-29 20:33:20 +000037#else // don't print debugging info
Damien George1dc76af2014-02-26 16:57:08 +000038#define DEBUG_printf(...) (void)0
Damien George2d15c122014-01-29 20:33:20 +000039#endif
40
Paul Sokolovskyef181022014-01-03 03:06:25 +020041#if MICROPY_MEM_STATS
Damien Georgeb4b10fd2015-01-01 23:30:53 +000042#define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); }
Paul Sokolovskyef181022014-01-03 03:06:25 +020043#endif
Damien429d7192013-10-04 19:53:11 +010044
Paul Sokolovskyb62c30b2014-02-10 22:37:09 +020045#if MICROPY_ENABLE_GC
Damien George51dfcb42015-01-01 20:27:54 +000046#include "py/gc.h"
Paul Sokolovskyb62c30b2014-02-10 22:37:09 +020047
48// We redirect standard alloc functions to GC heap - just for the rest of
49// this module. In the rest of micropython source, system malloc can be
50// freely accessed - for interfacing with system and 3rd-party libs for
51// example. On the other hand, some (e.g. bare-metal) ports may use GC
52// heap as system heap, so, to avoid warnings, we do undef's first.
53#undef malloc
54#undef free
55#undef realloc
Damien George12bab722014-04-05 20:35:48 +010056#define malloc(b) gc_alloc((b), false)
57#define malloc_with_finaliser(b) gc_alloc((b), true)
Paul Sokolovskyb62c30b2014-02-10 22:37:09 +020058#define free gc_free
Damien Georgeade9a052015-06-13 21:53:22 +010059#define realloc(ptr, n) gc_realloc(ptr, n, true)
60#define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv)
61#else
Damien Georgee9d1a942016-02-23 13:53:38 +000062STATIC void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) {
63 if (allow_move) {
64 return realloc(ptr, n_bytes);
65 } else {
66 // We are asked to resize, but without moving the memory region pointed to
67 // by ptr. Unless the underlying memory manager has special provision for
68 // this behaviour there is nothing we can do except fail to resize.
69 return NULL;
70 }
71}
Paul Sokolovskyb62c30b2014-02-10 22:37:09 +020072#endif // MICROPY_ENABLE_GC
73
Damien Georgeb0261342014-09-23 18:10:17 +010074void *m_malloc(size_t num_bytes) {
Damien429d7192013-10-04 19:53:11 +010075 void *ptr = malloc(num_bytes);
Damien George37378f82014-10-23 12:02:00 +010076 if (ptr == NULL && num_bytes != 0) {
Damien George6902eed2014-04-04 10:52:59 +000077 return m_malloc_fail(num_bytes);
Damien429d7192013-10-04 19:53:11 +010078 }
Paul Sokolovskyef181022014-01-03 03:06:25 +020079#if MICROPY_MEM_STATS
Damien Georgeb4b10fd2015-01-01 23:30:53 +000080 MP_STATE_MEM(total_bytes_allocated) += num_bytes;
81 MP_STATE_MEM(current_bytes_allocated) += num_bytes;
Paul Sokolovsky780f5552014-01-01 23:42:21 +020082 UPDATE_PEAK();
Paul Sokolovskyef181022014-01-03 03:06:25 +020083#endif
Damien George2d15c122014-01-29 20:33:20 +000084 DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
Damien429d7192013-10-04 19:53:11 +010085 return ptr;
86}
87
Damien Georgeb0261342014-09-23 18:10:17 +010088void *m_malloc_maybe(size_t num_bytes) {
Damien Georgef0954e32014-04-10 14:38:25 +010089 void *ptr = malloc(num_bytes);
Damien Georgef0954e32014-04-10 14:38:25 +010090#if MICROPY_MEM_STATS
Damien Georgeb4b10fd2015-01-01 23:30:53 +000091 MP_STATE_MEM(total_bytes_allocated) += num_bytes;
92 MP_STATE_MEM(current_bytes_allocated) += num_bytes;
Damien Georgef0954e32014-04-10 14:38:25 +010093 UPDATE_PEAK();
94#endif
95 DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
96 return ptr;
97}
98
Damien George12bab722014-04-05 20:35:48 +010099#if MICROPY_ENABLE_FINALISER
Damien Georgeb0261342014-09-23 18:10:17 +0100100void *m_malloc_with_finaliser(size_t num_bytes) {
Damien George12bab722014-04-05 20:35:48 +0100101 void *ptr = malloc_with_finaliser(num_bytes);
Damien George37378f82014-10-23 12:02:00 +0100102 if (ptr == NULL && num_bytes != 0) {
Damien George12bab722014-04-05 20:35:48 +0100103 return m_malloc_fail(num_bytes);
mux4f7e9f52014-04-03 23:55:12 +0200104 }
105#if MICROPY_MEM_STATS
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000106 MP_STATE_MEM(total_bytes_allocated) += num_bytes;
107 MP_STATE_MEM(current_bytes_allocated) += num_bytes;
mux4f7e9f52014-04-03 23:55:12 +0200108 UPDATE_PEAK();
109#endif
110 DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
111 return ptr;
112}
Damien George12bab722014-04-05 20:35:48 +0100113#endif
mux4f7e9f52014-04-03 23:55:12 +0200114
Damien Georgeb0261342014-09-23 18:10:17 +0100115void *m_malloc0(size_t num_bytes) {
Paul Sokolovsky58ff93b2014-02-10 18:37:11 +0200116 void *ptr = m_malloc(num_bytes);
Damien George37378f82014-10-23 12:02:00 +0100117 if (ptr == NULL && num_bytes != 0) {
118 return m_malloc_fail(num_bytes);
Damien429d7192013-10-04 19:53:11 +0100119 }
Damien George5ffe1d82016-08-26 15:35:26 +1000120 // If this config is set then the GC clears all memory, so we don't need to.
121 #if !MICROPY_GC_CONSERVATIVE_CLEAR
Damien George37378f82014-10-23 12:02:00 +0100122 memset(ptr, 0, num_bytes);
Damien George5ffe1d82016-08-26 15:35:26 +1000123 #endif
Damien429d7192013-10-04 19:53:11 +0100124 return ptr;
125}
126
Damien Georged8914522015-02-27 09:54:12 +0000127#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
Damien Georgeb0261342014-09-23 18:10:17 +0100128void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
Damien Georged8914522015-02-27 09:54:12 +0000129#else
130void *m_realloc(void *ptr, size_t new_num_bytes) {
131#endif
Paul Sokolovskycdd2c622014-01-30 03:58:17 +0200132 void *new_ptr = realloc(ptr, new_num_bytes);
Damien George37378f82014-10-23 12:02:00 +0100133 if (new_ptr == NULL && new_num_bytes != 0) {
Damien George6902eed2014-04-04 10:52:59 +0000134 return m_malloc_fail(new_num_bytes);
Damien429d7192013-10-04 19:53:11 +0100135 }
Paul Sokolovskyef181022014-01-03 03:06:25 +0200136#if MICROPY_MEM_STATS
Paul Sokolovsky43f1c802014-01-01 23:04:25 +0200137 // At first thought, "Total bytes allocated" should only grow,
138 // after all, it's *total*. But consider for example 2K block
139 // shrunk to 1K and then grown to 2K again. It's still 2K
140 // allocated total. If we process only positive increments,
141 // we'll count 3K.
Damien Georgeb0261342014-09-23 18:10:17 +0100142 size_t diff = new_num_bytes - old_num_bytes;
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000143 MP_STATE_MEM(total_bytes_allocated) += diff;
144 MP_STATE_MEM(current_bytes_allocated) += diff;
Paul Sokolovsky780f5552014-01-01 23:42:21 +0200145 UPDATE_PEAK();
Paul Sokolovskyef181022014-01-03 03:06:25 +0200146#endif
Paul Sokolovskycdd2c622014-01-30 03:58:17 +0200147 DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
148 return new_ptr;
Damien429d7192013-10-04 19:53:11 +0100149}
150
Damien Georged8914522015-02-27 09:54:12 +0000151#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
Damien Georgeade9a052015-06-13 21:53:22 +0100152void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move) {
Damien Georged8914522015-02-27 09:54:12 +0000153#else
Damien Georgeade9a052015-06-13 21:53:22 +0100154void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) {
Damien Georged8914522015-02-27 09:54:12 +0000155#endif
Damien Georgeade9a052015-06-13 21:53:22 +0100156 void *new_ptr = realloc_ext(ptr, new_num_bytes, allow_move);
Damien George58ba4c32014-04-10 14:27:31 +0000157#if MICROPY_MEM_STATS
158 // At first thought, "Total bytes allocated" should only grow,
159 // after all, it's *total*. But consider for example 2K block
160 // shrunk to 1K and then grown to 2K again. It's still 2K
161 // allocated total. If we process only positive increments,
162 // we'll count 3K.
Damien George37378f82014-10-23 12:02:00 +0100163 // Also, don't count failed reallocs.
164 if (!(new_ptr == NULL && new_num_bytes != 0)) {
165 size_t diff = new_num_bytes - old_num_bytes;
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000166 MP_STATE_MEM(total_bytes_allocated) += diff;
167 MP_STATE_MEM(current_bytes_allocated) += diff;
Damien George37378f82014-10-23 12:02:00 +0100168 UPDATE_PEAK();
169 }
Damien George58ba4c32014-04-10 14:27:31 +0000170#endif
171 DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
172 return new_ptr;
173}
174
Damien Georged8914522015-02-27 09:54:12 +0000175#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
Damien Georgeb0261342014-09-23 18:10:17 +0100176void m_free(void *ptr, size_t num_bytes) {
Damien Georged8914522015-02-27 09:54:12 +0000177#else
178void m_free(void *ptr) {
179#endif
Damien George37378f82014-10-23 12:02:00 +0100180 free(ptr);
Paul Sokolovskyef181022014-01-03 03:06:25 +0200181#if MICROPY_MEM_STATS
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000182 MP_STATE_MEM(current_bytes_allocated) -= num_bytes;
Paul Sokolovskyef181022014-01-03 03:06:25 +0200183#endif
Damien George2d15c122014-01-29 20:33:20 +0000184 DEBUG_printf("free %p, %d\n", ptr, num_bytes);
Damien732407f2013-12-29 19:33:23 +0000185}
186
Paul Sokolovskyef181022014-01-03 03:06:25 +0200187#if MICROPY_MEM_STATS
Damien Georgeb0261342014-09-23 18:10:17 +0100188size_t m_get_total_bytes_allocated(void) {
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000189 return MP_STATE_MEM(total_bytes_allocated);
Damien429d7192013-10-04 19:53:11 +0100190}
Paul Sokolovsky02de0c52014-01-01 23:15:47 +0200191
Damien Georgeb0261342014-09-23 18:10:17 +0100192size_t m_get_current_bytes_allocated(void) {
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000193 return MP_STATE_MEM(current_bytes_allocated);
Paul Sokolovsky02de0c52014-01-01 23:15:47 +0200194}
Paul Sokolovsky780f5552014-01-01 23:42:21 +0200195
Damien Georgeb0261342014-09-23 18:10:17 +0100196size_t m_get_peak_bytes_allocated(void) {
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000197 return MP_STATE_MEM(peak_bytes_allocated);
Paul Sokolovsky780f5552014-01-01 23:42:21 +0200198}
Damien Georgeb0261342014-09-23 18:10:17 +0100199#endif