mirror of
https://github.com/lua/lua
synced 2024-11-25 22:29:39 +03:00
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.
This commit is contained in:
parent
024a6071ca
commit
d36a31e673
23
lmem.c
23
lmem.c
@ -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)
|
||||
|
9
lvm.c
9
lvm.c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user