aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-18 14:58:15 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-18 14:58:15 -0300
commitd36a31e6739bcd39c84f637344227af87cfd0ee5 (patch)
tree68b0049215b0b6cf2a8109e24cb154175bf02c4d
parent024a6071cac749504e0b26a915bda4f52c41a892 (diff)
downloadlua-d36a31e6739bcd39c84f637344227af87cfd0ee5.tar.gz
lua-d36a31e6739bcd39c84f637344227af87cfd0ee5.tar.bz2
lua-d36a31e6739bcd39c84f637344227af87cfd0ee5.zip
Reviving HARDMEMTESTS
This commit brings a new implementation for HARDMEMTESTS, which forces an emergency GC whenever possible. It also fixes some issues detected with this option: - A small bug in lvm.c: a closure could be collected by an emergency GC while being initialized. - Some tests: a memory address can be immediatly reused after a GC; for instance, two consecutive '{}' expressions can return exactly the same address, if the first one is not anchored.
-rw-r--r--lmem.c23
-rw-r--r--lvm.c9
-rw-r--r--testes/api.lua7
-rw-r--r--testes/strings.lua11
4 files changed, 35 insertions, 15 deletions
diff --git a/lmem.c b/lmem.c
index 53f8dcb9..0186a86b 100644
--- a/lmem.c
+++ b/lmem.c
@@ -23,14 +23,25 @@
23 23
24 24
25#if defined(HARDMEMTESTS) 25#if defined(HARDMEMTESTS)
26#define hardtest(L,os,s) /* force a GC whenever possible */ \ 26/*
27 if ((s) > (os) && (G(L))->gcrunning) luaC_fullgc(L, 1); 27** First allocation will fail whenever not building initial state
28** and not shrinking a block. (This fail will trigger 'tryagain' and
29** a full GC cycle at every alocation.)
30*/
31static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
32 if (ttisnil(&g->nilvalue) && ns > os)
33 return NULL; /* fail */
34 else /* normal allocation */
35 return (*g->frealloc)(g->ud, block, os, ns);
36}
28#else 37#else
29#define hardtest(L,os,s) ((void)0) 38#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
30#endif 39#endif
31 40
32 41
33 42
43
44
34/* 45/*
35** About the realloc function: 46** About the realloc function:
36** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); 47** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
@@ -138,8 +149,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
138 void *newblock; 149 void *newblock;
139 global_State *g = G(L); 150 global_State *g = G(L);
140 lua_assert((osize == 0) == (block == NULL)); 151 lua_assert((osize == 0) == (block == NULL));
141 hardtest(L, osize, nsize); 152 newblock = firsttry(g, block, osize, nsize);
142 newblock = (*g->frealloc)(g->ud, block, osize, nsize);
143 if (unlikely(newblock == NULL && nsize > 0)) { 153 if (unlikely(newblock == NULL && nsize > 0)) {
144 if (nsize > osize) /* not shrinking a block? */ 154 if (nsize > osize) /* not shrinking a block? */
145 newblock = tryagain(L, block, osize, nsize); 155 newblock = tryagain(L, block, osize, nsize);
@@ -162,12 +172,11 @@ void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
162 172
163 173
164void *luaM_malloc_ (lua_State *L, size_t size, int tag) { 174void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
165 hardtest(L, 0, size);
166 if (size == 0) 175 if (size == 0)
167 return NULL; /* that's all */ 176 return NULL; /* that's all */
168 else { 177 else {
169 global_State *g = G(L); 178 global_State *g = G(L);
170 void *newblock = (*g->frealloc)(g->ud, NULL, tag, size); 179 void *newblock = firsttry(g, NULL, tag, size);
171 if (unlikely(newblock == NULL)) { 180 if (unlikely(newblock == NULL)) {
172 newblock = tryagain(L, NULL, tag, size); 181 newblock = tryagain(L, NULL, tag, size);
173 if (newblock == NULL) 182 if (newblock == NULL)
diff --git a/lvm.c b/lvm.c
index c1b6749d..d9bd0ab3 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1038,7 +1038,10 @@ void luaV_finishOp (lua_State *L) {
1038** errors. (That is, it will not return to the interpreter main loop 1038** errors. (That is, it will not return to the interpreter main loop
1039** after changing the stack or hooks.) 1039** after changing the stack or hooks.)
1040*/ 1040*/
1041#define halfProtect(exp) (savepc(L), (exp)) 1041#define halfProtect(exp) (savestate(L,ci), (exp))
1042
1043/* idem, but without changing the stack */
1044#define halfProtectNT(exp) (savepc(L), (exp))
1042 1045
1043 1046
1044#define checkGC(L,c) \ 1047#define checkGC(L,c) \
@@ -1620,7 +1623,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1620 vmcase(OP_RETURN0) { 1623 vmcase(OP_RETURN0) {
1621 if (L->hookmask) { 1624 if (L->hookmask) {
1622 L->top = ra; 1625 L->top = ra;
1623 halfProtect(luaD_poscall(L, ci, 0)); /* no hurry... */ 1626 halfProtectNT(luaD_poscall(L, ci, 0)); /* no hurry... */
1624 } 1627 }
1625 else { /* do the 'poscall' here */ 1628 else { /* do the 'poscall' here */
1626 int nres = ci->nresults; 1629 int nres = ci->nresults;
@@ -1634,7 +1637,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1634 vmcase(OP_RETURN1) { 1637 vmcase(OP_RETURN1) {
1635 if (L->hookmask) { 1638 if (L->hookmask) {
1636 L->top = ra + 1; 1639 L->top = ra + 1;
1637 halfProtect(luaD_poscall(L, ci, 1)); /* no hurry... */ 1640 halfProtectNT(luaD_poscall(L, ci, 1)); /* no hurry... */
1638 } 1641 }
1639 else { /* do the 'poscall' here */ 1642 else { /* do the 'poscall' here */
1640 int nres = ci->nresults; 1643 int nres = ci->nresults;
diff --git a/testes/api.lua b/testes/api.lua
index 8f4e89ac..5da03641 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -354,8 +354,11 @@ assert(to("topointer", nil) == null)
354assert(to("topointer", "abc") ~= null) 354assert(to("topointer", "abc") ~= null)
355assert(to("topointer", string.rep("x", 10)) == 355assert(to("topointer", string.rep("x", 10)) ==
356 to("topointer", string.rep("x", 10))) -- short strings 356 to("topointer", string.rep("x", 10))) -- short strings
357assert(to("topointer", string.rep("x", 300)) ~= 357do -- long strings
358 to("topointer", string.rep("x", 300))) -- long strings 358 local s1 = string.rep("x", 300)
359 local s2 = string.rep("x", 300)
360 assert(to("topointer", s1) ~= to("topointer", s2))
361end
359assert(to("topointer", T.pushuserdata(20)) ~= null) 362assert(to("topointer", T.pushuserdata(20)) ~= null)
360assert(to("topointer", io.read) ~= null) -- light C function 363assert(to("topointer", io.read) ~= null) -- light C function
361assert(to("topointer", hfunc) ~= null) -- "heavy" C function 364assert(to("topointer", hfunc) ~= null) -- "heavy" C function
diff --git a/testes/strings.lua b/testes/strings.lua
index 1b2b570e..2540fdef 100644
--- a/testes/strings.lua
+++ b/testes/strings.lua
@@ -163,11 +163,16 @@ do -- tests for '%p' format
163 assert(string.format("%p", 4) == null) 163 assert(string.format("%p", 4) == null)
164 assert(string.format("%p", print) ~= null) 164 assert(string.format("%p", print) ~= null)
165 assert(string.format("%p", coroutine.running()) ~= null) 165 assert(string.format("%p", coroutine.running()) ~= null)
166 assert(string.format("%p", {}) ~= string.format("%p", {})) 166 do
167 local t1 = {}; local t2 = {}
168 assert(string.format("%p", t1) ~= string.format("%p", t2))
169 end
167 assert(string.format("%p", string.rep("a", 10)) == 170 assert(string.format("%p", string.rep("a", 10)) ==
168 string.format("%p", string.rep("a", 10))) -- short strings 171 string.format("%p", string.rep("a", 10))) -- short strings
169 assert(string.format("%p", string.rep("a", 300)) ~= 172 do -- long strings
170 string.format("%p", string.rep("a", 300))) -- long strings 173 local s1 = string.rep("a", 300); local s2 = string.rep("a", 300)
174 assert(string.format("%p", s1) ~= string.format("%p", s2))
175 end
171 assert(#string.format("%90p", {}) == 90) 176 assert(#string.format("%90p", {}) == 90)
172end 177end
173 178