1 /* $NetBSD: lmem.c,v 1.11 2023/06/08 21:12:08 nikita Exp $ */ 2 3 /* 4 ** Id: lmem.c 5 ** Interface to Memory Manager 6 ** See Copyright Notice in lua.h 7 */ 8 9 #define lmem_c 10 #define LUA_CORE 11 12 #include "lprefix.h" 13 14 15 #ifndef _KERNEL 16 #include <stddef.h> 17 #endif /* _KERNEL */ 18 19 #include "lua.h" 20 21 #include "ldebug.h" 22 #include "ldo.h" 23 #include "lgc.h" 24 #include "lmem.h" 25 #include "lobject.h" 26 #include "lstate.h" 27 28 29 30 /* 31 ** About the realloc function: 32 ** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize); 33 ** ('osize' is the old size, 'nsize' is the new size) 34 ** 35 ** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL. 36 ** Particularly, frealloc(ud, NULL, 0, 0) does nothing, 37 ** which is equivalent to free(NULL) in ISO C. 38 ** 39 ** - frealloc(ud, NULL, x, s) creates a new block of size 's' 40 ** (no matter 'x'). Returns NULL if it cannot create the new block. 41 ** 42 ** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from 43 ** size 'x' to size 'y'. Returns NULL if it cannot reallocate the 44 ** block to the new size. 45 */ 46 47 48 /* 49 ** Macro to call the allocation function. 50 */ 51 #define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns)) 52 53 54 /* 55 ** When an allocation fails, it will try again after an emergency 56 ** collection, except when it cannot run a collection. The GC should 57 ** not be called while the state is not fully built, as the collector 58 ** is not yet fully initialized. Also, it should not be called when 59 ** 'gcstopem' is true, because then the interpreter is in the middle of 60 ** a collection step. 61 */ 62 #define cantryagain(g) (completestate(g) && !g->gcstopem) 63 64 65 66 67 #if defined(EMERGENCYGCTESTS) 68 /* 69 ** First allocation will fail except when freeing a block (frees never 70 ** fail) and when it cannot try again; this fail will trigger 'tryagain' 71 ** and a full GC cycle at every allocation. 72 */ 73 static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { 74 if (ns > 0 && cantryagain(g)) 75 return NULL; /* fail */ 76 else /* normal allocation */ 77 return callfrealloc(g, block, os, ns); 78 } 79 #else 80 #define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns) 81 #endif 82 83 84 85 86 87 /* 88 ** {================================================================== 89 ** Functions to allocate/deallocate arrays for the Parser 90 ** =================================================================== 91 */ 92 93 /* 94 ** Minimum size for arrays during parsing, to avoid overhead of 95 ** reallocating to size 1, then 2, and then 4. All these arrays 96 ** will be reallocated to exact sizes or erased when parsing ends. 97 */ 98 #define MINSIZEARRAY 4 99 100 101 void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, 102 int size_elems, int limit, const char *what) { 103 void *newblock; 104 int size = *psize; 105 if (nelems + 1 <= size) /* does one extra element still fit? */ 106 return block; /* nothing to be done */ 107 if (size >= limit / 2) { /* cannot double it? */ 108 if (l_unlikely(size >= limit)) /* cannot grow even a little? */ 109 luaG_runerror(L, "too many %s (limit is %d)", what, limit); 110 size = limit; /* still have at least one free place */ 111 } 112 else { 113 size *= 2; 114 if (size < MINSIZEARRAY) 115 size = MINSIZEARRAY; /* minimum size */ 116 } 117 lua_assert(nelems + 1 <= size && size <= limit); 118 /* 'limit' ensures that multiplication will not overflow */ 119 newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems, 120 cast_sizet(size) * size_elems); 121 *psize = size; /* update only when everything else is OK */ 122 return newblock; 123 } 124 125 126 /* 127 ** In prototypes, the size of the array is also its number of 128 ** elements (to save memory). So, if it cannot shrink an array 129 ** to its number of elements, the only option is to raise an 130 ** error. 131 */ 132 void *luaM_shrinkvector_ (lua_State *L, void *block, int *size, 133 int final_n, int size_elem) { 134 void *newblock; 135 size_t oldsize = cast_sizet((*size) * size_elem); 136 size_t newsize = cast_sizet(final_n * size_elem); 137 lua_assert(newsize <= oldsize); 138 newblock = luaM_saferealloc_(L, block, oldsize, newsize); 139 *size = final_n; 140 return newblock; 141 } 142 143 /* }================================================================== */ 144 145 146 l_noret luaM_toobig (lua_State *L) { 147 luaG_runerror(L, "memory allocation error: block too big"); 148 } 149 150 151 /* 152 ** Free memory 153 */ 154 void luaM_free_ (lua_State *L, void *block, size_t osize) { 155 global_State *g = G(L); 156 lua_assert((osize == 0) == (block == NULL)); 157 callfrealloc(g, block, osize, 0); 158 g->GCdebt -= osize; 159 } 160 161 162 /* 163 ** In case of allocation fail, this function will do an emergency 164 ** collection to free some memory and then try the allocation again. 165 */ 166 static void *tryagain (lua_State *L, void *block, 167 size_t osize, size_t nsize) { 168 global_State *g = G(L); 169 if (cantryagain(g)) { 170 luaC_fullgc(L, 1); /* try to free some memory... */ 171 return callfrealloc(g, block, osize, nsize); /* try again */ 172 } 173 else return NULL; /* cannot run an emergency collection */ 174 } 175 176 177 /* 178 ** Generic allocation routine. 179 */ 180 void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { 181 void *newblock; 182 global_State *g = G(L); 183 lua_assert((osize == 0) == (block == NULL)); 184 newblock = firsttry(g, block, osize, nsize); 185 if (l_unlikely(newblock == NULL && nsize > 0)) { 186 newblock = tryagain(L, block, osize, nsize); 187 if (newblock == NULL) /* still no memory? */ 188 return NULL; /* do not update 'GCdebt' */ 189 } 190 lua_assert((nsize == 0) == (newblock == NULL)); 191 g->GCdebt = (g->GCdebt + nsize) - osize; 192 return newblock; 193 } 194 195 196 void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, 197 size_t nsize) { 198 void *newblock = luaM_realloc_(L, block, osize, nsize); 199 if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ 200 luaM_error(L); 201 return newblock; 202 } 203 204 205 void *luaM_malloc_ (lua_State *L, size_t size, int tag) { 206 if (size == 0) 207 return NULL; /* that's all */ 208 else { 209 global_State *g = G(L); 210 void *newblock = firsttry(g, NULL, tag, size); 211 if (l_unlikely(newblock == NULL)) { 212 newblock = tryagain(L, NULL, tag, size); 213 if (newblock == NULL) 214 luaM_error(L); 215 } 216 g->GCdebt += size; 217 return newblock; 218 } 219 } 220