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-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.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 @@ | |||
| 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 | */ | ||
| 31 | static 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 | ||
| 164 | void *luaM_malloc_ (lua_State *L, size_t size, int tag) { | 174 | void *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) |
| @@ -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) | |||
| 354 | assert(to("topointer", "abc") ~= null) | 354 | assert(to("topointer", "abc") ~= null) |
| 355 | assert(to("topointer", string.rep("x", 10)) == | 355 | assert(to("topointer", string.rep("x", 10)) == |
| 356 | to("topointer", string.rep("x", 10))) -- short strings | 356 | to("topointer", string.rep("x", 10))) -- short strings |
| 357 | assert(to("topointer", string.rep("x", 300)) ~= | 357 | do -- 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)) | ||
| 361 | end | ||
| 359 | assert(to("topointer", T.pushuserdata(20)) ~= null) | 362 | assert(to("topointer", T.pushuserdata(20)) ~= null) |
| 360 | assert(to("topointer", io.read) ~= null) -- light C function | 363 | assert(to("topointer", io.read) ~= null) -- light C function |
| 361 | assert(to("topointer", hfunc) ~= null) -- "heavy" C function | 364 | 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 | |||
| 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) |
| 172 | end | 177 | end |
| 173 | 178 | ||
