xref: /freebsd/contrib/lua/src/lmem.c (revision a9490b81b032b43cdb3c8c76b4d01bbad9ff82c1)
18e3e3a7aSWarner Losh /*
20495ed39SKyle Evans ** $Id: lmem.c $
38e3e3a7aSWarner Losh ** Interface to Memory Manager
48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h
58e3e3a7aSWarner Losh */
68e3e3a7aSWarner Losh 
78e3e3a7aSWarner Losh #define lmem_c
88e3e3a7aSWarner Losh #define LUA_CORE
98e3e3a7aSWarner Losh 
108e3e3a7aSWarner Losh #include "lprefix.h"
118e3e3a7aSWarner Losh 
128e3e3a7aSWarner Losh 
138e3e3a7aSWarner Losh #include <stddef.h>
148e3e3a7aSWarner Losh 
158e3e3a7aSWarner Losh #include "lua.h"
168e3e3a7aSWarner Losh 
178e3e3a7aSWarner Losh #include "ldebug.h"
188e3e3a7aSWarner Losh #include "ldo.h"
198e3e3a7aSWarner Losh #include "lgc.h"
208e3e3a7aSWarner Losh #include "lmem.h"
218e3e3a7aSWarner Losh #include "lobject.h"
228e3e3a7aSWarner Losh #include "lstate.h"
238e3e3a7aSWarner Losh 
248e3e3a7aSWarner Losh 
258e3e3a7aSWarner Losh 
268e3e3a7aSWarner Losh /*
278e3e3a7aSWarner Losh ** About the realloc function:
288e3e3a7aSWarner Losh ** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
298e3e3a7aSWarner Losh ** ('osize' is the old size, 'nsize' is the new size)
308e3e3a7aSWarner Losh **
310495ed39SKyle Evans ** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL.
320495ed39SKyle Evans ** Particularly, frealloc(ud, NULL, 0, 0) does nothing,
330495ed39SKyle Evans ** which is equivalent to free(NULL) in ISO C.
348e3e3a7aSWarner Losh **
350495ed39SKyle Evans ** - frealloc(ud, NULL, x, s) creates a new block of size 's'
360495ed39SKyle Evans ** (no matter 'x'). Returns NULL if it cannot create the new block.
378e3e3a7aSWarner Losh **
380495ed39SKyle Evans ** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from
390495ed39SKyle Evans ** size 'x' to size 'y'. Returns NULL if it cannot reallocate the
400495ed39SKyle Evans ** block to the new size.
418e3e3a7aSWarner Losh */
428e3e3a7aSWarner Losh 
438e3e3a7aSWarner Losh 
44*a9490b81SWarner Losh /*
45*a9490b81SWarner Losh ** Macro to call the allocation function.
46*a9490b81SWarner Losh */
47*a9490b81SWarner Losh #define callfrealloc(g,block,os,ns)    ((*g->frealloc)(g->ud, block, os, ns))
48*a9490b81SWarner Losh 
49*a9490b81SWarner Losh 
50*a9490b81SWarner Losh /*
51*a9490b81SWarner Losh ** When an allocation fails, it will try again after an emergency
52*a9490b81SWarner Losh ** collection, except when it cannot run a collection.  The GC should
53*a9490b81SWarner Losh ** not be called while the state is not fully built, as the collector
54*a9490b81SWarner Losh ** is not yet fully initialized. Also, it should not be called when
55*a9490b81SWarner Losh ** 'gcstopem' is true, because then the interpreter is in the middle of
56*a9490b81SWarner Losh ** a collection step.
57*a9490b81SWarner Losh */
58*a9490b81SWarner Losh #define cantryagain(g)	(completestate(g) && !g->gcstopem)
59*a9490b81SWarner Losh 
60*a9490b81SWarner Losh 
61*a9490b81SWarner Losh 
62*a9490b81SWarner Losh 
63*a9490b81SWarner Losh #if defined(EMERGENCYGCTESTS)
64*a9490b81SWarner Losh /*
65*a9490b81SWarner Losh ** First allocation will fail except when freeing a block (frees never
66*a9490b81SWarner Losh ** fail) and when it cannot try again; this fail will trigger 'tryagain'
67*a9490b81SWarner Losh ** and a full GC cycle at every allocation.
68*a9490b81SWarner Losh */
firsttry(global_State * g,void * block,size_t os,size_t ns)69*a9490b81SWarner Losh static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
70*a9490b81SWarner Losh   if (ns > 0 && cantryagain(g))
71*a9490b81SWarner Losh     return NULL;  /* fail */
72*a9490b81SWarner Losh   else  /* normal allocation */
73*a9490b81SWarner Losh     return callfrealloc(g, block, os, ns);
74*a9490b81SWarner Losh }
75*a9490b81SWarner Losh #else
76*a9490b81SWarner Losh #define firsttry(g,block,os,ns)    callfrealloc(g, block, os, ns)
77*a9490b81SWarner Losh #endif
78*a9490b81SWarner Losh 
79*a9490b81SWarner Losh 
80*a9490b81SWarner Losh 
818e3e3a7aSWarner Losh 
820495ed39SKyle Evans 
830495ed39SKyle Evans /*
840495ed39SKyle Evans ** {==================================================================
850495ed39SKyle Evans ** Functions to allocate/deallocate arrays for the Parser
860495ed39SKyle Evans ** ===================================================================
870495ed39SKyle Evans */
880495ed39SKyle Evans 
890495ed39SKyle Evans /*
900495ed39SKyle Evans ** Minimum size for arrays during parsing, to avoid overhead of
910495ed39SKyle Evans ** reallocating to size 1, then 2, and then 4. All these arrays
920495ed39SKyle Evans ** will be reallocated to exact sizes or erased when parsing ends.
930495ed39SKyle Evans */
948e3e3a7aSWarner Losh #define MINSIZEARRAY	4
958e3e3a7aSWarner Losh 
968e3e3a7aSWarner Losh 
luaM_growaux_(lua_State * L,void * block,int nelems,int * psize,int size_elems,int limit,const char * what)970495ed39SKyle Evans void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
980495ed39SKyle Evans                      int size_elems, int limit, const char *what) {
998e3e3a7aSWarner Losh   void *newblock;
1000495ed39SKyle Evans   int size = *psize;
1010495ed39SKyle Evans   if (nelems + 1 <= size)  /* does one extra element still fit? */
1020495ed39SKyle Evans     return block;  /* nothing to be done */
1030495ed39SKyle Evans   if (size >= limit / 2) {  /* cannot double it? */
1048c784bb8SWarner Losh     if (l_unlikely(size >= limit))  /* cannot grow even a little? */
1058e3e3a7aSWarner Losh       luaG_runerror(L, "too many %s (limit is %d)", what, limit);
1060495ed39SKyle Evans     size = limit;  /* still have at least one free place */
1078e3e3a7aSWarner Losh   }
1088e3e3a7aSWarner Losh   else {
1090495ed39SKyle Evans     size *= 2;
1100495ed39SKyle Evans     if (size < MINSIZEARRAY)
1110495ed39SKyle Evans       size = MINSIZEARRAY;  /* minimum size */
1128e3e3a7aSWarner Losh   }
1130495ed39SKyle Evans   lua_assert(nelems + 1 <= size && size <= limit);
1140495ed39SKyle Evans   /* 'limit' ensures that multiplication will not overflow */
1150495ed39SKyle Evans   newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems,
1160495ed39SKyle Evans                                          cast_sizet(size) * size_elems);
1170495ed39SKyle Evans   *psize = size;  /* update only when everything else is OK */
1188e3e3a7aSWarner Losh   return newblock;
1198e3e3a7aSWarner Losh }
1208e3e3a7aSWarner Losh 
1218e3e3a7aSWarner Losh 
1220495ed39SKyle Evans /*
1230495ed39SKyle Evans ** In prototypes, the size of the array is also its number of
1240495ed39SKyle Evans ** elements (to save memory). So, if it cannot shrink an array
1250495ed39SKyle Evans ** to its number of elements, the only option is to raise an
1260495ed39SKyle Evans ** error.
1270495ed39SKyle Evans */
luaM_shrinkvector_(lua_State * L,void * block,int * size,int final_n,int size_elem)1280495ed39SKyle Evans void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
1290495ed39SKyle Evans                           int final_n, int size_elem) {
1300495ed39SKyle Evans   void *newblock;
1310495ed39SKyle Evans   size_t oldsize = cast_sizet((*size) * size_elem);
1320495ed39SKyle Evans   size_t newsize = cast_sizet(final_n * size_elem);
1330495ed39SKyle Evans   lua_assert(newsize <= oldsize);
1340495ed39SKyle Evans   newblock = luaM_saferealloc_(L, block, oldsize, newsize);
1350495ed39SKyle Evans   *size = final_n;
1360495ed39SKyle Evans   return newblock;
1370495ed39SKyle Evans }
1380495ed39SKyle Evans 
1390495ed39SKyle Evans /* }================================================================== */
1400495ed39SKyle Evans 
1410495ed39SKyle Evans 
luaM_toobig(lua_State * L)1428e3e3a7aSWarner Losh l_noret luaM_toobig (lua_State *L) {
1438e3e3a7aSWarner Losh   luaG_runerror(L, "memory allocation error: block too big");
1448e3e3a7aSWarner Losh }
1458e3e3a7aSWarner Losh 
1468e3e3a7aSWarner Losh 
1470495ed39SKyle Evans /*
1480495ed39SKyle Evans ** Free memory
1490495ed39SKyle Evans */
luaM_free_(lua_State * L,void * block,size_t osize)1500495ed39SKyle Evans void luaM_free_ (lua_State *L, void *block, size_t osize) {
1510495ed39SKyle Evans   global_State *g = G(L);
1520495ed39SKyle Evans   lua_assert((osize == 0) == (block == NULL));
153*a9490b81SWarner Losh   callfrealloc(g, block, osize, 0);
1540495ed39SKyle Evans   g->GCdebt -= osize;
1550495ed39SKyle Evans }
1560495ed39SKyle Evans 
1578e3e3a7aSWarner Losh 
1588e3e3a7aSWarner Losh /*
1598c784bb8SWarner Losh ** In case of allocation fail, this function will do an emergency
1608c784bb8SWarner Losh ** collection to free some memory and then try the allocation again.
1610495ed39SKyle Evans */
tryagain(lua_State * L,void * block,size_t osize,size_t nsize)1620495ed39SKyle Evans static void *tryagain (lua_State *L, void *block,
1630495ed39SKyle Evans                        size_t osize, size_t nsize) {
1640495ed39SKyle Evans   global_State *g = G(L);
165*a9490b81SWarner Losh   if (cantryagain(g)) {
1660495ed39SKyle Evans     luaC_fullgc(L, 1);  /* try to free some memory... */
167*a9490b81SWarner Losh     return callfrealloc(g, block, osize, nsize);  /* try again */
1680495ed39SKyle Evans   }
169*a9490b81SWarner Losh   else return NULL;  /* cannot run an emergency collection */
1700495ed39SKyle Evans }
1710495ed39SKyle Evans 
1720495ed39SKyle Evans 
1730495ed39SKyle Evans /*
1740495ed39SKyle Evans ** Generic allocation routine.
1758e3e3a7aSWarner Losh */
luaM_realloc_(lua_State * L,void * block,size_t osize,size_t nsize)1768e3e3a7aSWarner Losh void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
1778e3e3a7aSWarner Losh   void *newblock;
1788e3e3a7aSWarner Losh   global_State *g = G(L);
1790495ed39SKyle Evans   lua_assert((osize == 0) == (block == NULL));
1800495ed39SKyle Evans   newblock = firsttry(g, block, osize, nsize);
1818c784bb8SWarner Losh   if (l_unlikely(newblock == NULL && nsize > 0)) {
1820495ed39SKyle Evans     newblock = tryagain(L, block, osize, nsize);
1830495ed39SKyle Evans     if (newblock == NULL)  /* still no memory? */
1840495ed39SKyle Evans       return NULL;  /* do not update 'GCdebt' */
1858e3e3a7aSWarner Losh   }
1868e3e3a7aSWarner Losh   lua_assert((nsize == 0) == (newblock == NULL));
1870495ed39SKyle Evans   g->GCdebt = (g->GCdebt + nsize) - osize;
1888e3e3a7aSWarner Losh   return newblock;
1898e3e3a7aSWarner Losh }
1908e3e3a7aSWarner Losh 
1910495ed39SKyle Evans 
luaM_saferealloc_(lua_State * L,void * block,size_t osize,size_t nsize)1920495ed39SKyle Evans void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
1930495ed39SKyle Evans                                                     size_t nsize) {
1940495ed39SKyle Evans   void *newblock = luaM_realloc_(L, block, osize, nsize);
1958c784bb8SWarner Losh   if (l_unlikely(newblock == NULL && nsize > 0))  /* allocation failed? */
1960495ed39SKyle Evans     luaM_error(L);
1970495ed39SKyle Evans   return newblock;
1980495ed39SKyle Evans }
1990495ed39SKyle Evans 
2000495ed39SKyle Evans 
luaM_malloc_(lua_State * L,size_t size,int tag)2010495ed39SKyle Evans void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
2020495ed39SKyle Evans   if (size == 0)
2030495ed39SKyle Evans     return NULL;  /* that's all */
2040495ed39SKyle Evans   else {
2050495ed39SKyle Evans     global_State *g = G(L);
2060495ed39SKyle Evans     void *newblock = firsttry(g, NULL, tag, size);
2078c784bb8SWarner Losh     if (l_unlikely(newblock == NULL)) {
2080495ed39SKyle Evans       newblock = tryagain(L, NULL, tag, size);
2090495ed39SKyle Evans       if (newblock == NULL)
2100495ed39SKyle Evans         luaM_error(L);
2110495ed39SKyle Evans     }
2120495ed39SKyle Evans     g->GCdebt += size;
2130495ed39SKyle Evans     return newblock;
2140495ed39SKyle Evans   }
2150495ed39SKyle Evans }
216