Browse Source

avoid using one function for different tasks (malloc, free, etc.)

Roberto Ierusalimschy 7 years ago
parent
commit
49dfaf7447
3 changed files with 108 additions and 47 deletions
  1. 66 11
      lmem.c
  2. 33 20
      lmem.h
  3. 9 16
      lparser.c

+ 66 - 11
lmem.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.c,v 1.90 2015/03/03 18:18:29 roberto Exp roberto $
+** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp roberto $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */
@@ -22,6 +22,14 @@
 #include "lstate.h"
 
 
+#if defined(HARDMEMTESTS)
+#define hardtest(L,os,s)  /* force a GC whenever possible */ \
+  if ((s) > (os) && (G(L))->gcrunning) luaC_fullgc(L, 1);
+#else
+#define hardtest(L,os,s)  ((void)0)
+#endif
+
+
 
 /*
 ** About the realloc function:
@@ -45,10 +53,12 @@
 #define MINSIZEARRAY	4
 
 
-void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
-                     int limit, const char *what) {
+void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *size,
+                     int size_elems, int limit, const char *what) {
   void *newblock;
   int newsize;
+  if (nelems + 1 <= *size)  /* does one extra element still fit? */
+    return block;  /* nothing to be done */
   if (*size >= limit/2) {  /* cannot double it? */
     if (*size >= limit)  /* cannot grow even a little? */
       luaG_runerror(L, "too many %s (limit is %d)", what, limit);
@@ -65,11 +75,40 @@ void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
 }
 
 
+void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
+                          int final_n, int size_elem) {
+  global_State *g = G(L);
+  void *newblock;
+  size_t oldsize = cast(size_t, (*size) * size_elem);
+  size_t newsize = cast(size_t, final_n * size_elem);
+  lua_assert(newsize <= oldsize);
+  newblock = (*g->frealloc)(g->ud, block, oldsize, newsize);
+  if (newblock == NULL && final_n > 0)  /* allocation failed? */
+    return block;  /* keep old block */
+  else {
+    g->GCdebt += newsize - oldsize;
+    *size = final_n;
+    return newblock;
+  }
+}
+
+
 l_noret luaM_toobig (lua_State *L) {
   luaG_runerror(L, "memory allocation error: block too big");
 }
 
 
+/*
+** Free memory
+*/
+void luaM_free_ (lua_State *L, void *block, size_t osize) {
+  global_State *g = G(L);
+  lua_assert((block == 0) == (block == NULL));
+  (*g->frealloc)(g->ud, block, osize, 0);
+  g->GCdebt -= osize;
+}
+
+
 
 /*
 ** generic allocation routine.
@@ -77,15 +116,11 @@ l_noret luaM_toobig (lua_State *L) {
 void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
   void *newblock;
   global_State *g = G(L);
-  size_t realosize = (block) ? osize : 0;
-  lua_assert((realosize == 0) == (block == NULL));
-#if defined(HARDMEMTESTS)
-  if (nsize > realosize && g->gcrunning)
-    luaC_fullgc(L, 1);  /* force a GC whenever possible */
-#endif
+  lua_assert((osize == 0) == (block == NULL));
+  hardtest(L, osize, nsize);
   newblock = (*g->frealloc)(g->ud, block, osize, nsize);
   if (newblock == NULL && nsize > 0) {
-    lua_assert(nsize > realosize);  /* cannot fail when shrinking a block */
+    lua_assert(nsize > osize);  /* cannot fail when shrinking a block */
     if (g->version) {  /* is state fully built? */
       luaC_fullgc(L, 1);  /* try to free some memory... */
       newblock = (*g->frealloc)(g->ud, block, osize, nsize);  /* try again */
@@ -94,7 +129,27 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
       luaD_throw(L, LUA_ERRMEM);
   }
   lua_assert((nsize == 0) == (newblock == NULL));
-  g->GCdebt = (g->GCdebt + nsize) - realosize;
+  g->GCdebt = (g->GCdebt + nsize) - osize;
   return newblock;
 }
 
+
+void *luaM_malloc (lua_State *L, size_t size, int tag) {
+  hardtest(L, 0, size);
+  if (size == 0)
+    return NULL;  /* that's all */
+  else {
+    global_State *g = G(L);
+    void *newblock = (*g->frealloc)(g->ud, NULL, tag, size);
+    if (newblock == NULL) {
+      if (g->version) {  /* is state fully built? */
+        luaC_fullgc(L, 1);  /* try to free some memory... */
+        newblock = (*g->frealloc)(g->ud, NULL, tag, size);  /* try again */
+      }
+      if (newblock == NULL)
+        luaD_throw(L, LUA_ERRMEM);
+    }
+    g->GCdebt += size;
+    return newblock;
+  }
+}

+ 33 - 20
lmem.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.h,v 1.42 2014/12/19 13:45:40 roberto Exp roberto $
+** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp roberto $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */
@@ -15,11 +15,9 @@
 
 
 /*
-** This macro reallocs a vector 'b' from 'on' to 'n' elements, where
-** each element has size 'e'. In case of arithmetic overflow of the
-** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because
-** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e).
-**
+** This macro tests whether it is safe to multiply 'n' by the size of
+** type 't' without overflows. Because 'e' is always constant, it avoids
+** the runtime division MAX_SIZET/(e).
 ** (The macro is somewhat complex to avoid warnings:  The 'sizeof'
 ** comparison avoids a runtime comparison when overflow cannot occur.
 ** The compiler should be able to optimize the real test by itself, but
@@ -27,10 +25,20 @@
 ** false due to limited range of data type"; the +1 tricks the compiler,
 ** avoiding this warning but also this optimization.)
 */
+#define luaM_testsize(n,e)  \
+	(sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e))
+
+#define luaM_checksize(L,n,e)  \
+	(luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0))
+
+/*
+** This macro reallocs a vector 'b' from 'on' to 'n' elements, where
+** each element has size 'e'. In case of arithmetic overflow of the
+** product 'n'*'e', it raises an error (calling 'luaM_toobig').
+*/
 #define luaM_reallocv(L,b,on,n,e) \
-  (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \
-      ? luaM_toobig(L) : cast_void(0)) , \
-   luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
+  (luaM_checksize(L,n,e), \
+   luaM_realloc_(L, (b), cast(size_t, on)*(e), cast(size_t, n)*(e)))
 
 /*
 ** Arrays of chars do not need any test
@@ -38,32 +46,37 @@
 #define luaM_reallocvchar(L,b,on,n)  \
     cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char)))
 
-#define luaM_freemem(L, b, s)	luaM_realloc_(L, (b), (s), 0)
-#define luaM_free(L, b)		luaM_realloc_(L, (b), sizeof(*(b)), 0)
-#define luaM_freearray(L, b, n)   luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0)
+#define luaM_freemem(L, b, s)	luaM_free_(L, (b), (s))
+#define luaM_free(L, b)		luaM_free_(L, (b), sizeof(*(b)))
+#define luaM_freearray(L, b, n)   luaM_free_(L, (b), (n)*sizeof(*(b)))
 
-#define luaM_malloc(L,s)	luaM_realloc_(L, NULL, 0, (s))
-#define luaM_new(L,t)		cast(t *, luaM_malloc(L, sizeof(t)))
+#define luaM_new(L,t)		cast(t *, luaM_malloc(L, sizeof(t), 0))
 #define luaM_newvector(L,n,t) \
-		cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
+  (luaM_checksize(L,n,sizeof(t)), cast(t *, luaM_malloc(L, (n)*sizeof(t), 0)))
 
-#define luaM_newobject(L,tag,s)	luaM_realloc_(L, NULL, tag, (s))
+#define luaM_newobject(L,tag,s)	luaM_malloc(L, (s), tag)
 
 #define luaM_growvector(L,v,nelems,size,t,limit,e) \
-          if ((nelems)+1 > (size)) \
-            ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
+	((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t),limit,e)))
 
 #define luaM_reallocvector(L, v,oldn,n,t) \
    ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
 
+#define luaM_shrinkvector(L,v,size,fs,t) \
+   ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t))))
+
 LUAI_FUNC l_noret luaM_toobig (lua_State *L);
 
 /* not to be called directly */
 LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
                                                           size_t size);
-LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
-                               size_t size_elem, int limit,
+LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
+LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
+                               int *size, int size_elem, int limit,
                                const char *what);
+LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
+                                    int final_n, int size_elem);
+LUAI_FUNC void *luaM_malloc (lua_State *L, size_t size, int tag);
 
 #endif
 

+ 9 - 16
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.168 2017/11/23 16:35:54 roberto Exp roberto $
+** $Id: lparser.c,v 2.169 2017/11/30 13:29:18 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -569,21 +569,14 @@ static void close_func (LexState *ls) {
   luaK_ret(fs, 0, 0);  /* final return */
   leaveblock(fs);
   luaK_finish(fs);
-  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
-  f->sizecode = fs->pc;
-  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte);
-  f->sizelineinfo = fs->pc;
-  luaM_reallocvector(L, f->abslineinfo, f->sizeabslineinfo,
-                        fs->nabslineinfo, AbsLineInfo);
-  f->sizeabslineinfo = fs->nabslineinfo;
-  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
-  f->sizek = fs->nk;
-  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
-  f->sizep = fs->np;
-  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
-  f->sizelocvars = fs->nlocvars;
-  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
-  f->sizeupvalues = fs->nups;
+  luaM_shrinkvector(L, f->code, f->sizecode, fs->pc, Instruction);
+  luaM_shrinkvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte);
+  luaM_shrinkvector(L, f->abslineinfo, f->sizeabslineinfo,
+                       fs->nabslineinfo, AbsLineInfo);
+  luaM_shrinkvector(L, f->k, f->sizek, fs->nk, TValue);
+  luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
+  luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
+  luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
   lua_assert(fs->bl == NULL);
   ls->fs = fs->prev;
   luaC_checkGC(L);