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 | ||