diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-18 14:58:15 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-18 14:58:15 -0300 |
| commit | d36a31e6739bcd39c84f637344227af87cfd0ee5 (patch) | |
| tree | 68b0049215b0b6cf2a8109e24cb154175bf02c4d | |
| parent | 024a6071cac749504e0b26a915bda4f52c41a892 (diff) | |
| download | lua-github-d36a31e6739bcd39c84f637344227af87cfd0ee5.tar.gz | |
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.c | 23 | ||||
| -rw-r--r-- | lvm.c | 9 | ||||
| -rw-r--r-- | testes/api.lua | 7 | ||||
| -rw-r--r-- | testes/strings.lua | 11 |
4 files changed, 35 insertions, 15 deletions
@@ -23,14 +23,25 @@ #if defined(HARDMEMTESTS) -#define hardtest(L,os,s) /* force a GC whenever possible */ \ - if ((s) > (os) && (G(L))->gcrunning) luaC_fullgc(L, 1); +/* +** First allocation will fail whenever not building initial state +** and not shrinking a block. (This fail will trigger 'tryagain' and +** a full GC cycle at every alocation.) +*/ +static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { + if (ttisnil(&g->nilvalue) && ns > os) + return NULL; /* fail */ + else /* normal allocation */ + return (*g->frealloc)(g->ud, block, os, ns); +} #else -#define hardtest(L,os,s) ((void)0) +#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns)) #endif + + /* ** About the realloc function: ** 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) { void *newblock; global_State *g = G(L); lua_assert((osize == 0) == (block == NULL)); - hardtest(L, osize, nsize); - newblock = (*g->frealloc)(g->ud, block, osize, nsize); + newblock = firsttry(g, block, osize, nsize); if (unlikely(newblock == NULL && nsize > 0)) { if (nsize > osize) /* not shrinking a block? */ newblock = tryagain(L, block, osize, nsize); @@ -162,12 +172,11 @@ void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, 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); + void *newblock = firsttry(g, NULL, tag, size); if (unlikely(newblock == NULL)) { newblock = tryagain(L, NULL, tag, size); if (newblock == NULL) @@ -1038,7 +1038,10 @@ void luaV_finishOp (lua_State *L) { ** errors. (That is, it will not return to the interpreter main loop ** after changing the stack or hooks.) */ -#define halfProtect(exp) (savepc(L), (exp)) +#define halfProtect(exp) (savestate(L,ci), (exp)) + +/* idem, but without changing the stack */ +#define halfProtectNT(exp) (savepc(L), (exp)) #define checkGC(L,c) \ @@ -1620,7 +1623,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmcase(OP_RETURN0) { if (L->hookmask) { L->top = ra; - halfProtect(luaD_poscall(L, ci, 0)); /* no hurry... */ + halfProtectNT(luaD_poscall(L, ci, 0)); /* no hurry... */ } else { /* do the 'poscall' here */ int nres = ci->nresults; @@ -1634,7 +1637,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmcase(OP_RETURN1) { if (L->hookmask) { L->top = ra + 1; - halfProtect(luaD_poscall(L, ci, 1)); /* no hurry... */ + halfProtectNT(luaD_poscall(L, ci, 1)); /* no hurry... */ } else { /* do the 'poscall' here */ 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) assert(to("topointer", "abc") ~= null) assert(to("topointer", string.rep("x", 10)) == to("topointer", string.rep("x", 10))) -- short strings -assert(to("topointer", string.rep("x", 300)) ~= - to("topointer", string.rep("x", 300))) -- long strings +do -- long strings + local s1 = string.rep("x", 300) + local s2 = string.rep("x", 300) + assert(to("topointer", s1) ~= to("topointer", s2)) +end assert(to("topointer", T.pushuserdata(20)) ~= null) assert(to("topointer", io.read) ~= null) -- light C function assert(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 assert(string.format("%p", 4) == null) assert(string.format("%p", print) ~= null) assert(string.format("%p", coroutine.running()) ~= null) - assert(string.format("%p", {}) ~= string.format("%p", {})) + do + local t1 = {}; local t2 = {} + assert(string.format("%p", t1) ~= string.format("%p", t2)) + end assert(string.format("%p", string.rep("a", 10)) == string.format("%p", string.rep("a", 10))) -- short strings - assert(string.format("%p", string.rep("a", 300)) ~= - string.format("%p", string.rep("a", 300))) -- long strings + do -- long strings + local s1 = string.rep("a", 300); local s2 = string.rep("a", 300) + assert(string.format("%p", s1) ~= string.format("%p", s2)) + end assert(#string.format("%90p", {}) == 90) end |
