Home | History | Annotate | Line # | Download | only in src
      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