Compare commits

...

8 Commits

@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $
** $Id: lgc.h $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@ -25,25 +25,18 @@
*/
/* how much to allocate before next GC step */
#if !defined(GCSTEPSIZE)
/* ~100 small strings */
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
#endif
/*
** Possible states of the Garbage Collector
*/
#define GCSpropagate 0
#define GCSatomic 1
#define GCSswpallgc 2
#define GCSswpfinobj 3
#define GCSswptobefnz 4
#define GCSswpend 5
#define GCScallfin 6
#define GCSpause 7
#define GCSenteratomic 1
#define GCSatomic 2
#define GCSswpallgc 3
#define GCSswpfinobj 4
#define GCSswptobefnz 5
#define GCSswpend 6
#define GCScallfin 7
#define GCSpause 8
#define issweepphase(g) \
@ -64,7 +57,7 @@
/*
** some useful bit tricks
*/
#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
#define resetbits(x,m) ((x) &= cast_byte(~(m)))
#define setbits(x,m) ((x) |= (m))
#define testbits(x,m) ((x) & (m))
#define bitmask(b) (1<<(b))
@ -74,12 +67,17 @@
#define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in 'marked' field: */
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been marked for finalization */
/* bit 7 is currently used by tests (luaL_checkmemory) */
/*
** Layout for bit use in 'marked' field. First three bits are
** used for object "age" in generational mode. Last bit is free
** to be used by respective objects.
*/
#define WHITE0BIT 3 /* object is white (type 0) */
#define WHITE1BIT 4 /* object is white (type 1) */
#define BLACKBIT 5 /* object is black */
#define FINALIZEDBIT 6 /* object has been marked for finalization */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
@ -92,14 +90,60 @@
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdeadm(ow,m) ((m) & (ow))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
#define changewhite(x) ((x)->marked ^= WHITEBITS)
#define gray2black(x) l_setbit((x)->marked, BLACKBIT)
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS)
/* object age in generational mode */
#define G_NEW 0 /* created in current cycle */
#define G_SURVIVAL 1 /* created in previous cycle */
#define G_OLD0 2 /* marked old by frw. barrier in this cycle */
#define G_OLD1 3 /* first full cycle as old */
#define G_OLD 4 /* really old object (not to be visited) */
#define G_TOUCHED1 5 /* old object touched this cycle */
#define G_TOUCHED2 6 /* old object touched in previous cycle */
#define AGEBITS 7 /* all age bits (111) */
#define getage(o) ((o)->marked & AGEBITS)
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
#define isold(o) (getage(o) > G_SURVIVAL)
#define changeage(o,f,t) \
check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
/* Default Values for GC parameters */
#define LUAI_GENMAJORMUL 100
#define LUAI_GENMINORMUL 20
/* wait memory to double before starting new cycle */
#define LUAI_GCPAUSE 200
/*
** some gc parameters are stored divided by 4 to allow a maximum value
** up to 1023 in a 'lu_byte'.
*/
#define getgcparam(p) ((p) * 4)
#define setgcparam(p,v) ((p) = (v) / 4)
#define LUAI_GCMUL 100
/* how much to allocate before next GC step (log2) */
#define LUAI_GCSTEPSIZE 13 /* 8 KB */
/*
** Check whether the declared GC mode is generational. While in
** generational mode, the collector can go temporarily to incremental
** mode to improve performance. This is signaled by 'g->lastatomic != 0'.
*/
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
@ -127,9 +171,9 @@
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) ( \
(iscollectable((uv)->v) && !upisopen(uv)) ? \
luaC_upvalbarrier_(L,uv) : cast_void(0))
#define luaC_upvalbarrier(L,uv,x) ( \
(iscollectable(x) && !upisopen(uv)) ? \
luaC_upvalbarrier_(L,gcvalue(x)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
@ -138,10 +182,12 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_upvalbarrier_(lua_State* L, GCObject* o);
LUAI_FUNC void luaC_upvalbarrier_compat(lua_State* L, UpVal* uv);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#endif

@ -52,6 +52,23 @@ typedef signed char ls_byte;
#define MAX_INT INT_MAX /* maximum value of an int */
/*
** floor of the log2 of the maximum signed value for integral type 't'.
** (That is, maximum 'n' such that '2^n' fits in the given signed type.)
*/
#define log2maxs(t) (sizeof(t) * 8 - 2)
/*
** test whether an unsigned value is a power of 2 (or zero)
*/
#define ispow2(x) (((x) & ((x) - 1)) == 0)
/* number of chars of a literal string without the ending \0 */
#define LL(x) (sizeof(x)/sizeof(char) - 1)
/*
** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer

@ -27,6 +27,22 @@
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
**
** For the generational collector, some of these lists have marks for
** generations. Each mark points to the first element in the list for
** that particular generation; that generation goes until the next mark.
**
** 'allgc' -> 'survival': new objects;
** 'survival' -> 'old': objects that survived one collection;
** 'old' -> 'reallyold': objects that became old in last collection;
** 'reallyold' -> NULL: objects old for more than one cycle.
**
** 'finobj' -> 'finobjsur': new objects marked for finalization;
** 'finobjsur' -> 'finobjold': survived """";
** 'finobjold' -> 'finobjrold': just old """";
** 'finobjrold' -> NULL: really old """".
*/
/*
** Moreover, there is another set of lists that control gray objects.
** These lists are linked by fields 'gclist'. (All objects that
** can become gray have such a field. The field is not the same
@ -43,7 +59,7 @@
** 'weak': tables with weak values to be cleared;
** 'ephemeron': ephemeron tables with white->white entries;
** 'allweak': tables with weak keys and/or weak values to be cleared.
** The last three lists are used only during the atomic phase.
*/
@ -69,8 +85,8 @@ struct lua_longjmp; /* defined in ldo.c */
/* kinds of Garbage Collection */
#define KGC_NORMAL 0
#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
#define KGC_INC 0 /* incremental gc */
#define KGC_GEN 1 /* generational gc */
typedef struct stringtable {
@ -146,15 +162,21 @@ typedef struct global_State {
void *ud; /* auxiliary data to 'frealloc' */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */
stringtable strt; /* hash table for strings */
TValue l_registry;
unsigned int seed; /* randomized seed for hashes */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */
lu_byte gcrunning; /* true if GC is running */
lu_byte gcemergency; /* true if this is an emergency collection */
lu_byte gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */
lu_byte gcstepsize; /* (log2 of) GC granularity */
GCObject *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */
@ -165,10 +187,14 @@ typedef struct global_State {
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
/* fields for generational collector */
GCObject *survival; /* start of objects that survived one GC cycle */
GCObject *old; /* start of old objects */
GCObject *reallyold; /* old objects with more than one cycle */
GCObject *finobjsur; /* list of survival objects with finalizers */
GCObject *finobjold; /* list of old objects with finalizers */
GCObject *finobjrold; /* list of really old objects with finalizers */
struct lua_State *twups; /* list of threads with open upvalues */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread;
const lua_Number *version; /* pointer to version number */

@ -117,7 +117,7 @@ LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
LUAI_FUNC int luaH_getn (Table *t);
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
/* RAVI array specialization */

@ -164,6 +164,7 @@ typedef struct Memcontrol {
unsigned long total;
unsigned long maxmem;
unsigned long memlimit;
unsigned long countlimit;
unsigned long objcount[LUA_NUMTAGS];
} Memcontrol;
@ -394,8 +395,10 @@ LUA_API int (lua_isyieldable) (lua_State *L);
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9
#define LUA_GCGEN 10
#define LUA_GCINC 11
LUA_API int (lua_gc) (lua_State *L, int what, int data);
LUA_API int (lua_gc) (lua_State *L, int what, ...);
/*

@ -96,7 +96,7 @@
*/
#define luaV_finishfastset(L,t,slot,v) \
{ setobj2t(L, cast(TValue *,slot), v); \
luaC_barrierback(L, hvalue(t), v); }
luaC_barrierback(L, gcvalue(t), v); }

@ -1069,10 +1069,11 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
o = index2addr(L, idx);
api_check(L, ttistable(o), "table expected");
if (ttisLtable(o)) {
slot = luaH_set(L, hvalue(o), L->top - 2);
setobj2t(L, slot, L->top - 1);
invalidateTMcache(hvalue(o));
luaC_barrierback(L, hvalue(o), L->top - 1);
luaC_barrierback(L, gcvalue(o), L->top - 1);
}
else if (ttisfarray(o)) {
RaviArray *t = arrvalue(o);
@ -1124,7 +1125,7 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
api_check(L, ttistable(o), "table expected");
if (ttisLtable(o)) {
luaH_setint(L, hvalue(o), n, L->top - 1);
luaC_barrierback(L, hvalue(o), L->top - 1);
luaC_barrierback(L, gcvalue(o), L->top - 1);
}
else if (ttisfarray(o)) {
RaviArray *t = arrvalue(o);
@ -1166,7 +1167,7 @@ LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
setpvalue(&k, cast(void *, p));
slot = luaH_set(L, hvalue(o), &k);
setobj2t(L, slot, L->top - 1);
luaC_barrierback(L, hvalue(o), L->top - 1);
luaC_barrierback(L, gcvalue(o), L->top - 1);
L->top--;
lua_unlock(L);
}
@ -1345,7 +1346,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt);
luaC_upvalbarrier(L, f->upvals[0]);
luaC_upvalbarrier(L, f->upvals[0], gt);
}
}
lua_unlock(L);
@ -1376,12 +1377,12 @@ LUA_API int lua_status (lua_State *L) {
/*
** Garbage-collection function
*/
LUA_API int lua_gc (lua_State *L, int what, int data) {
LUA_API int lua_gc (lua_State *L, int what, ...) {
va_list argp;
int res = 0;
global_State *g;
global_State *g = G(L);
lua_lock(L);
g = G(L);
va_start(argp, what);
switch (what) {
case LUA_GCSTOP: {
g->gcrunning = 0;
@ -1406,11 +1407,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSTEP: {
int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */
lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L);
}
else { /* add 'data' to total debt */
@ -1424,22 +1426,49 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSETPAUSE: {
res = g->gcpause;
g->gcpause = data;
int data = va_arg(argp, int);
res = getgcparam(g->gcpause);
setgcparam(g->gcpause, data);
break;
}
case LUA_GCSETSTEPMUL: {
res = g->gcstepmul;
if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */
g->gcstepmul = data;
int data = va_arg(argp, int);
res = getgcparam(g->gcstepmul);
setgcparam(g->gcstepmul, data);
break;
}
case LUA_GCISRUNNING: {
res = g->gcrunning;
break;
}
case LUA_GCGEN: {
int minormul = va_arg(argp, int);
int majormul = va_arg(argp, int);
res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC;
if (minormul != 0)
g->genminormul = minormul;
if (majormul != 0)
setgcparam(g->genmajormul, majormul);
luaC_changemode(L, KGC_GEN);
break;
}
case LUA_GCINC: {
int pause = va_arg(argp, int);
int stepmul = va_arg(argp, int);
int stepsize = va_arg(argp, int);
res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC;
if (pause != 0)
setgcparam(g->gcpause, pause);
if (stepmul != 0)
setgcparam(g->gcstepmul, stepmul);
if (stepsize != 0)
g->gcstepsize = stepsize;
luaC_changemode(L, KGC_INC);
break;
}
default: res = -1; /* invalid option */
}
va_end(argp);
lua_unlock(L);
return res;
}
@ -1611,8 +1640,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
if (name) {
L->top--;
setobj(L, val, L->top);
if (owner) { luaC_barrier(L, owner, L->top); }
else if (uv) { luaC_upvalbarrier(L, uv); }
if (owner) { luaC_barrier(L, owner, val); }
else if (uv) { luaC_upvalbarrier(L, uv, val); }
}
lua_unlock(L);
return name;
@ -1661,7 +1690,7 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
*up1 = *up2;
(*up1)->refcount++;
if (upisopen(*up1)) (*up1)->u.open.touched = 1;
luaC_upvalbarrier(L, *up1);
luaC_upvalbarrier(L, *up1, (*up1)->v);
}
}

@ -170,27 +170,58 @@ static int luaB_rawset (lua_State *L) {
}
static int pushmode (lua_State *L, int oldmode) {
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational");
return 1;
}
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"isrunning", NULL};
"isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCISRUNNING};
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, ex);
switch (o) {
case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0);
lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024));
int k = lua_gc(L, o);
int b = lua_gc(L, LUA_GCCOUNTB);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1;
}
case LUA_GCSTEP: case LUA_GCISRUNNING: {
case LUA_GCSTEP: {
int step = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, step);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCSETPAUSE:
case LUA_GCSETSTEPMUL: {
int p = (int)luaL_optinteger(L, 2, 0);
int previous = lua_gc(L, o, p);
lua_pushinteger(L, previous);
return 1;
}
case LUA_GCISRUNNING: {
int res = lua_gc(L, o);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCGEN: {
int minormul = (int)luaL_optinteger(L, 2, 0);
int majormul = (int)luaL_optinteger(L, 3, 0);
return pushmode(L, lua_gc(L, o, minormul, majormul));
}
case LUA_GCINC: {
int pause = (int)luaL_optinteger(L, 2, 0);
int stepmul = (int)luaL_optinteger(L, 3, 0);
int stepsize = (int)luaL_optinteger(L, 4, 0);
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
}
default: {
int res = lua_gc(L, o);
lua_pushinteger(L, res);
return 1;
}

@ -168,9 +168,10 @@ int luaF_close (lua_State *L, StkId level, int status) {
}
}
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
luaC_upvalbarrier(L, uv);
TValue* slot = &uv->u.value; /* new position for value */
setobj(L, slot, uv->v); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */
luaC_upvalbarrier(L, uv, slot);
}
}
return status;
@ -184,9 +185,10 @@ void luaF_close (lua_State *L, StkId level) {
if (uv->refcount == 0) /* no references? */
luaM_free(L, uv); /* free upvalue */
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
luaC_upvalbarrier(L, uv);
TValue* slot = &uv->u.value; /* new position for value */
setobj(L, slot, uv->v); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */
luaC_upvalbarrier(L, uv, slot);
}
}
}

File diff suppressed because it is too large Load Diff

@ -962,6 +962,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
fs->bl = NULL;
f = fs->f;
f->source = ls->source;
luaC_objbarrier(ls->L, f, f->source);
f->maxstacksize = 2; /* registers 0/1 are always valid */
enterblock(fs, bl, 0);
DEBUG_VARS(raviY_printf(fs, "open_func -> fs->firstlocal set to %d (ls->dyd->actvar.n), and fs->nactvar reset to 0\n", ls->dyd->actvar.n));
@ -2463,6 +2464,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0, RAVI_TANY, NULL); /* create and... - RAVI TODO var arg is unknown type */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaC_objbarrier(ls->L, fs->f, ls->envn);
luaX_next(ls); /* read first token */
statlist(ls); /* parse main body */
check(ls, TK_EOS);
@ -2481,8 +2483,9 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
sethvalue(L, L->top, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
luaC_objbarrier(L, funcstate.f, funcstate.f->source);
lexstate.buff = buff;
lexstate.dyd = dyd;
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;

@ -32,14 +32,6 @@
#include "ravi_profile.h"
#include "ravi_alloc.h"
#if !defined(LUAI_GCPAUSE)
#define LUAI_GCPAUSE 200 /* 200% */
#endif
#if !defined(LUAI_GCMUL)
#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
#endif
/*
** a macro to help the creation of a unique random seed when a state is
@ -362,31 +354,38 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g);
preinit_thread(L, g);
g->allgc = obj2gco(L); /* by now, only object is the main thread */
L->next = NULL;
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->seed = makeseed(L);
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
g->gckind = KGC_NORMAL;
g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
g->gckind = KGC_INC;
g->gcemergency = 0;
g->finobj = g->tobefnz = g->fixedgc = NULL;
g->survival = g->old = g->reallyold = NULL;
g->finobjsur = g->finobjold = g->finobjrold = NULL;
g->sweepgc = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->twups = NULL;
g->totalbytes = sizeof(LG);
g->GCdebt = 0;
g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
g->ravi_state = NULL;
g->lastatomic = 0;
setgcparam(g->gcpause, LUAI_GCPAUSE);
setgcparam(g->gcstepmul, LUAI_GCMUL);
g->gcstepsize = LUAI_GCSTEPSIZE;
setgcparam(g->genmajormul, LUAI_GENMAJORMUL);
g->genminormul = LUAI_GENMINORMUL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
g->ravi_state = NULL;
raviV_initjit(L);
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */

@ -614,7 +614,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
}
}
setnodekey(L, &mp->i_key, key);
luaC_barrierback(L, t, key);
luaC_barrierback(L, obj2gco(t), key);
lua_assert(ttisnil(gval(mp)));
return gval(mp);
}
@ -782,7 +782,7 @@ static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) {
** Try to find a boundary in table 't'. A 'boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
int luaH_getn (Table *t) {
lua_Unsigned luaH_getn (Table *t) {
unsigned int j;
j = t->sizearray;
if (j > 0 && ttisnil(&t->array[j - 1])) {
@ -816,7 +816,7 @@ static int ravi_resize_array(lua_State *L, RaviArray *t, unsigned int new_size,
unsigned int size = new_size < t->size + 10 ? t->size + 10 : new_size;
int was_allocated = t->flags & RAVI_ARRAY_ALLOCATED;
lua_assert(!was_allocated ? t->size == RAVI_ARRAY_MAX_INLINE : 1);
lua_assert(!was_allocated ? (t->data == &t->numarray || t->data == &t->intarray) : 1);
lua_assert(!was_allocated ? (t->data == (char*)&t->numarray || t->data == (char*)&t->intarray) : 1);
char *olddata = was_allocated ? t->data : NULL; // Not allocated
if (number_array) {
t->data = (char *)luaM_reallocv(L, olddata, t->size, size, sizeof(lua_Number));

@ -1,5 +1,5 @@
/*
** $Id: ltests.c,v 2.211 2016/12/04 20:17:24 roberto Exp $
** $Id: ltests.c $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -53,9 +53,8 @@ static int runC (lua_State *L, lua_State *L1, const char *pc);
static void setnameval (lua_State *L, const char *name, int val) {
lua_pushstring(L, name);
lua_pushinteger(L, val);
lua_settable(L, -3);
lua_setfield(L, -2, name);
}
@ -105,7 +104,7 @@ typedef union Header {
static Memcontrol l_memcontrol =
{0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}};
{0L, 0L, 0L, 0L, (~0UL), {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}};
LUA_API Memcontrol* luaB_getmemcontrol(void) {
return &l_memcontrol;
@ -147,7 +146,12 @@ LUA_API void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
freeblock(mc, block);
return NULL;
}
else if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
if (mc->countlimit != ~0UL && size != oldsize) { /* count limit in use? */
if (mc->countlimit == 0)
return NULL; /* fake a memory allocation error */
mc->countlimit--;
}
if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
return NULL; /* fake a memory allocation error */
else {
Header *newblock;
@ -156,7 +160,8 @@ LUA_API void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
size_t realsize = sizeof(Header) + size + MARKSIZE;
if (realsize < size) return NULL; /* arithmetic overflow! */
newblock = cast(Header *, malloc(realsize)); /* alloc a new block */
if (newblock == NULL) return NULL; /* really out of memory? */
if (newblock == NULL)
return NULL; /* really out of memory? */
if (block) {
memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */
freeblock(mc, block); /* erase (and check) old copy */
@ -189,18 +194,39 @@ LUA_API void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
*/
/*
** Check GC invariants. For incremental mode, a black object cannot
** point to a white one. For generational mode, really old objects
** cannot point to young objects. Both old1 and touched2 objects
** cannot point to new objects (but can point to survivals).
** (Threads and open upvalues, despite being marked "really old",
** continue to be visited in all collections, and therefore can point to
** new objects. They, and only they, are old but gray.)
*/
static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
if (isdead(g,t)) return 0;
if (!issweepphase(g))
return !(isblack(f) && iswhite(t));
else return 1;
if (issweepphase(g))
return 1; /* no invariants */
else if (g->gckind == KGC_INC)
return !(isblack(f) && iswhite(t)); /* basic incremental invariant */
else { /* generational mode */
if ((getage(f) == G_OLD && isblack(f)) && !isold(t))
return 0;
if (((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) && isblack(f)) &&
getage(t) == G_NEW)
return 0;
return 1;
}
}
static void printobj (global_State *g, GCObject *o) {
printf("||%s(%p)-%c(%02X)||",
printf("||%s(%p)-%c%c(%02X)||",
ttypename(novariant(o->tt)), (void *)o,
isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->marked);
isdead(g,o) ? 'd' : isblack(o) ? 'b' : iswhite(o) ? 'w' : 'g',
"ns01oTt"[getage(o)], o->marked);
if (o->tt == LUA_TSHRSTR || o->tt == LUA_TLNGSTR)
printf(" '%s'", getstr(gco2ts(o)));
}
@ -243,6 +269,15 @@ static void checktable (global_State *g, Table *h) {
}
static void checkudata (global_State *g, Udata *u) {
GCObject *hgc = obj2gco(u);
TValue uservalue;
Table *mt = u->metatable;
checkobjref(g, hgc, mt);
getuservalue(g->mainthread, u, &uservalue);
checkvalref(g, hgc, &uservalue);
}
/*
** All marks are conditional because a GC may happen while the
** prototype is still being created
@ -308,32 +343,26 @@ static void checkstack (global_State *g, lua_State *L1) {
CallInfo *ci;
UpVal *uv;
lua_assert(!isdead(g, L1));
if (L1->stack == NULL) { /* incomplete thread? */
lua_assert(L1->stacksize == 0 && L1->openupval == NULL &&
L1->ci == NULL);
return;
}
for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
lua_assert(upisopen(uv)); /* must be open */
for (ci = L1->ci; ci != NULL; ci = ci->previous) {
lua_assert(ci->top <= L1->stack_last);
lua_assert(lua_checkpc(L1, ci));
}
if (L1->stack) { /* complete thread? */
for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++)
checkliveness(L1, o); /* entire stack must have valid values */
}
else lua_assert(L1->stacksize == 0);
for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++)
checkliveness(L1, o); /* entire stack must have valid values */
}
static void checkobject (global_State *g, GCObject *o, int maybedead) {
if (isdead(g, o))
lua_assert(maybedead);
else {
lua_assert(g->gcstate != GCSpause || iswhite(o));
static void checkrefs (global_State *g, GCObject *o) {
switch (o->tt) {
case LUA_TUSERDATA: {
TValue uservalue;
Table *mt = gco2u(o)->metatable;
checkobjref(g, o, mt);
getuservalue(g->mainthread, gco2u(o), &uservalue);
checkvalref(g, o, &uservalue);
checkudata(g, gco2u(o));
break;
}
case LUA_TTABLE: {
@ -363,18 +392,46 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
}
default: lua_assert(0);
}
}
}
#define TESTGRAYBIT 7
/*
** Check consistency of an object:
** - Dead objects can only happen in the 'allgc' list during a sweep
** phase (controlled by the caller through 'maybedead').
** - During pause, all objects must be white.
** - In generational mode:
** * objects must be old enough for their lists ('listage').
** * old objects cannot be white.
** * old objects must be black, except for 'touched1', 'old0',
** threads, and open upvalues.
*/
static void checkobject (global_State *g, GCObject *o, int maybedead,
int listage) {
if (isdead(g, o))
lua_assert(maybedead);
else {
lua_assert(g->gcstate != GCSpause || iswhite(o));
if (g->gckind == KGC_GEN) { /* generational mode? */
lua_assert(getage(o) >= listage);
lua_assert(!iswhite(o) || !isold(o));
if (isold(o)) {
lua_assert(isblack(o) ||
getage(o) == G_TOUCHED1 ||
getage(o) == G_OLD0 ||
o->tt == LUA_TTHREAD /* ||
(o->tt == LUA_TUPVAL && upisopen(gco2upv(o)))*/);
}
}
checkrefs(g, o);
}
}
static void checkgraylist (global_State *g, GCObject *o) {
((void)g); /* better to keep it available if we need to print an object */
while (o) {
lua_assert(isgray(o));
lua_assert(!testbit(o->marked, TESTGRAYBIT));
l_setbit(o->marked, TESTGRAYBIT);
lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
switch (o->tt) {
case LUA_TTABLE: o = gco2t(o)->gclist; break;
case LUA_TLCL: o = gco2lcl(o)->gclist; break;
@ -388,26 +445,35 @@ static void checkgraylist (global_State *g, GCObject *o) {
/*
** mark all objects in gray lists with the TESTGRAYBIT, so that
** 'checkmemory' can check that all gray objects are in a gray list
** Check objects in gray lists.
*/
static void markgrays (global_State *g) {
static void checkgrays (global_State *g) {
if (!keepinvariant(g)) return;
checkgraylist(g, g->gray);
checkgraylist(g, g->grayagain);
checkgraylist(g, g->weak);
checkgraylist(g, g->ephemeron);
checkgraylist(g, g->allweak);
}
static void checkgray (global_State *g, GCObject *o) {
for (; o != NULL; o = o->next) {
if (isgray(o)) {
lua_assert(!keepinvariant(g) || testbit(o->marked, TESTGRAYBIT));
resetbit(o->marked, TESTGRAYBIT);
}
lua_assert(!testbit(o->marked, TESTGRAYBIT));
static void checklist (global_State *g, int maybedead, int tof,
GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) {
GCObject *o;
for (o = newl; o != survival; o = o->next) {
checkobject(g, o, maybedead, G_NEW);
lua_assert(!tof == !tofinalize(o));
}
for (o = survival; o != old; o = o->next) {
checkobject(g, o, 0, G_SURVIVAL);
lua_assert(!tof == !tofinalize(o));
}
for (o = old; o != reallyold; o = o->next) {
checkobject(g, o, 0, G_OLD1);
lua_assert(!tof == !tofinalize(o));
}
for (o = reallyold; o != NULL; o = o->next) {
checkobject(g, o, 0, G_OLD);
lua_assert(!tof == !tofinalize(o));
}
}
@ -421,32 +487,24 @@ int lua_checkmemory (lua_State *L) {
lua_assert(!iswhite(gcvalue(&g->l_registry)));
}
lua_assert(!isdead(g, gcvalue(&g->l_registry)));
checkstack(g, g->mainthread);
resetbit(g->mainthread->marked, TESTGRAYBIT);
lua_assert(g->sweepgc == NULL || issweepphase(g));
markgrays(g);
checkgrays(g);
/* check 'fixedgc' list */
for (o = g->fixedgc; o != NULL; o = o->next) {
lua_assert(o->tt == LUA_TSHRSTR && isgray(o));
lua_assert(o->tt == LUA_TSHRSTR && isgray(o) && getage(o) == G_OLD);
}
/* check 'allgc' list */
checkgray(g, g->allgc);
maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc);
for (o = g->allgc; o != NULL; o = o->next) {
checkobject(g, o, maybedead);
lua_assert(!tofinalize(o));
}
checklist(g, maybedead, 0, g->allgc, g->survival, g->old, g->reallyold);
/* check 'finobj' list */
checkgray(g, g->finobj);
for (o = g->finobj; o != NULL; o = o->next) {
checkobject(g, o, 0);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
checklist(g, 0, 1, g->finobj, g->finobjsur, g->finobjold, g->finobjrold);
/* check 'tobefnz' list */
checkgray(g, g->tobefnz);
for (o = g->tobefnz; o != NULL; o = o->next) {
checkobject(g, o, 0);
checkobject(g, o, 0, G_NEW);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
@ -605,11 +663,20 @@ static int mem_query (lua_State *L) {
return 1;
}
}
return luaL_error(L, "unkown type '%s'", t);
return luaL_error(L, "unknown type '%s'", t);
}
}
static int alloc_count (lua_State *L) {
if (lua_isnone(L, 1))
l_memcontrol.countlimit = ~0L;
else
l_memcontrol.countlimit = luaL_checkinteger(L, 1);
return 0;
}
static int settrick (lua_State *L) {
if (ttisnil(obj_at(L, 1)))
l_Trick = NULL;
@ -629,17 +696,50 @@ static int gc_color (lua_State *L) {
GCObject *obj = gcvalue(o);
lua_pushstring(L, isdead(G(L), obj) ? "dead" :
iswhite(obj) ? "white" :
isblack(obj) ? "black" : "grey");
isblack(obj) ? "black" : "gray");
}
return 1;
}
static int gc_age (lua_State *L) {
TValue *o;
luaL_checkany(L, 1);
o = obj_at(L, 1);
if (!iscollectable(o))
lua_pushstring(L, "no collectable");
else {
static const char *gennames[] = {"new", "survival", "old0", "old1",
"old", "touched1", "touched2"};
GCObject *obj = gcvalue(o);
lua_pushstring(L, gennames[getage(obj)]);
}
return 1;
}
static int gc_printobj (lua_State *L) {
TValue *o;
luaL_checkany(L, 1);
o = obj_at(L, 1);
if (!iscollectable(o))
printf("no collectable\n");
else {
GCObject *obj = gcvalue(o);
printobj(G(L), obj);
printf("\n");
}
return 0;
}
static int gc_state (lua_State *L) {
static const char *statenames[] = {"propagate", "atomic", "sweepallgc",
"sweepfinobj", "sweeptobefnz", "sweepend", "pause", ""};
static const int states[] = {GCSpropagate, GCSatomic, GCSswpallgc,
GCSswpfinobj, GCSswptobefnz, GCSswpend, GCSpause, -1};
static const char *statenames[] = {
"propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj",
"sweeptobefnz", "sweepend", "callfin", "pause", ""};
static const int states[] = {
GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj,
GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1};
int option = states[luaL_checkoption(L, 1, "", statenames)];
if (option == -1) {
lua_pushstring(L, statenames[G(L)->gcstate]);
@ -647,6 +747,8 @@ static int gc_state (lua_State *L) {
}
else {
global_State *g = G(L);
if (G(L)->gckind == KGC_GEN)
luaL_error(L, "cannot change states in generational mode");
lua_lock(L);
if (option < g->gcstate) { /* must cross 'pause'? */
luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */
@ -863,6 +965,7 @@ static int loadlib (lua_State *L) {
{"math", luaopen_math},
{"string", luaopen_string},
{"table", luaopen_table},
{"T", luaB_opentests},
{NULL, NULL}
};
lua_State *L1 = getstate(L);
@ -988,8 +1091,8 @@ static const char *const delimits = " \t\n,;";
static void skip (const char **pc) {
for (;;) {
if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
else if (**pc == '#') {
while (**pc != '\n' && **pc != '\0') (*pc)++;
else if (**pc == '#') { /* comment? */
while (**pc != '\n' && **pc != '\0') (*pc)++; /* until end-of-line */
}
else break;
}
@ -1234,7 +1337,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
else if EQ("pop") {
lua_pop(L1, getnum);
}
else if EQ("print") {
else if EQ("printstack") {
int n = getnum;
if (n != 0) {
printf("%s\n", luaL_tolstring(L1, n, NULL));
@ -1242,6 +1345,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
}
else printstack(L1);
}
else if EQ("print") {
const char *msg = getstring;
printf("%s\n", msg);
}
else if EQ("pushbool") {
lua_pushboolean(L1, getnum);
}
@ -1332,6 +1440,9 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
else if EQ("error") {
lua_error(L1);
}
else if EQ("abort") {
abort();
}
else if EQ("throw") {
#if defined(__cplusplus)
static struct X { int x; } x;
@ -1520,7 +1631,9 @@ static const struct luaL_Reg tests_funcs[] = {
{"doonnewstack", doonnewstack},
{"doremote", doremote},
{"gccolor", gc_color},
{"gcage", gc_age},
{"gcstate", gc_state},
{"pobj", gc_printobj},
{"getref", getref},
{"hash", hash_query},
{"int2fb", int2fb_aux},

@ -588,6 +588,7 @@ static int pmain (lua_State *L) {
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */

@ -244,7 +244,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h);
luaC_barrierback(L, h, val);
luaC_barrierback(L, obj2gco(h), val);
return;
}
/* else will try the metamethod */
@ -364,7 +364,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
slot = luaH_get(hvalue(t), key); \
if (!ttisnil(slot)) { \
setobj2t(L, cast(TValue *, slot), val); \
luaC_barrierback(L, hvalue(t), val); \
luaC_barrierback(L, gcvalue(t), val); \
} \
else { \
protect(luaV_finishset(L, t, key, val, slot)); \
@ -421,7 +421,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
slot = luaH_getint(h, idx); \
if (!ttisnil(slot)) { \
setobj2t(L, cast(TValue *, slot), val); \
luaC_barrierback(L, h, val); \
luaC_barrierback(L, obj2gco(h), val); \
} \
else { \
protect(luaV_finishset(L, t, key, val, slot)); \
@ -471,7 +471,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
const TValue *slot = luaH_getshortstr(hvalue(t), tsvalue(key)); \
if (!ttisnil(slot)) { \
setobj2t(L, cast(TValue *, slot), val); \
luaC_barrierback(L, hvalue(t), val); \
luaC_barrierback(L, gcvalue(t), val); \
} \
else { \
protect(luaV_finishset(L, t, key, val, slot)); \
@ -1358,7 +1358,7 @@ int luaV_execute (lua_State *L) {
vmcase(OP_SETUPVAL) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
vmbreak;
}
vmcase(OP_GETTABUP) {
@ -1896,7 +1896,7 @@ int luaV_execute (lua_State *L) {
for (; n > 0; n--) {
TValue *val = ra + n;
luaH_setint(L, h, last--, val);
luaC_barrierback(L, h, val);
luaC_barrierback(L, obj2gco(h), val);
}
}
else {
@ -2273,7 +2273,7 @@ int luaV_execute (lua_State *L) {
if (tointeger(ra, &ia)) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setivalue(uv->v, ia);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
else
luaG_runerror(
@ -2285,7 +2285,7 @@ int luaV_execute (lua_State *L) {
if (tonumber(ra, &na)) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setfltvalue(uv->v, na);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
else
luaG_runerror(
@ -2299,7 +2299,7 @@ int luaV_execute (lua_State *L) {
"integer[] value");
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
vmbreak;
}
vmcase(OP_RAVI_SETUPVAL_FARRAY) {
@ -2309,7 +2309,7 @@ int luaV_execute (lua_State *L) {
"upvalue of number[] type, cannot be set to non number[] value");
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
vmbreak;
}
vmcase(OP_RAVI_SETUPVALT) {
@ -2318,7 +2318,7 @@ int luaV_execute (lua_State *L) {
L, "upvalue of table type, cannot be set to non table value");
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
vmbreak;
}
vmcase(OP_RAVI_LOADIZ) {
@ -2570,7 +2570,7 @@ static void ravi_dump_ci(lua_State *L, CallInfo *ci) {
int func_type = ttype(func);
StkId base = NULL;
Proto *p = NULL;
int funcpos = ci->func - L->stack;
int funcpos = (int)(ci->func - L->stack);
StkId stack_ptr = ci->top - 1;
int i;
switch (func_type) {
@ -2589,7 +2589,7 @@ static void ravi_dump_ci(lua_State *L, CallInfo *ci) {
case LUA_TFUNCTION:
p = clLvalue(func)->p;
base = ci->u.l.base;
i = ci->top - L->stack - 1;
i = (int) (ci->top - L->stack - 1);
break;
default:
return;
@ -2730,7 +2730,7 @@ void raviV_op_setlist(lua_State *L, CallInfo *ci, TValue *ra, int b, int c) {
for (; n > 0; n--) {
TValue *val = ra + n;
luaH_setint(L, h, last--, val);
luaC_barrierback(L, h, val);
luaC_barrierback(L, obj2gco(h), val);
}
}
else {
@ -2835,7 +2835,7 @@ void raviV_op_setupvali(lua_State *L, LClosure *cl, TValue *ra, int b) {
if (tointeger(ra, &ia)) {
UpVal *uv = cl->upvals[b];
setivalue(uv->v, ia);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
else
luaG_runerror(
@ -2847,7 +2847,7 @@ void raviV_op_setupvalf(lua_State *L, LClosure *cl, TValue *ra, int b) {
if (tonumber(ra, &na)) {
UpVal *uv = cl->upvals[b];
setfltvalue(uv->v, na);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
else
luaG_runerror(L,
@ -2860,7 +2860,7 @@ void raviV_op_setupvalai(lua_State *L, LClosure *cl, TValue *ra, int b) {
L, "upvalue of integer[] type, cannot be set to non integer[] value");
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
void raviV_op_setupvalaf(lua_State *L, LClosure *cl, TValue *ra, int b) {
@ -2869,7 +2869,7 @@ void raviV_op_setupvalaf(lua_State *L, LClosure *cl, TValue *ra, int b) {
L, "upvalue of number[] type, cannot be set to non number[] value");
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
void raviV_op_setupvalt(lua_State *L, LClosure *cl, TValue *ra, int b) {
@ -2877,13 +2877,13 @@ void raviV_op_setupvalt(lua_State *L, LClosure *cl, TValue *ra, int b) {
luaG_runerror(L, "upvalue of table type, cannot be set to non table value");
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
void raviV_op_setupval(lua_State *L, LClosure *cl, TValue *ra, int b) {
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_upvalbarrier(L, uv, ra);
}
void raviV_op_add(lua_State *L, TValue *ra, TValue *rb, TValue *rc) {

@ -1142,7 +1142,7 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
"luaV_objlen");
def->luaC_upvalbarrierF = def->raviF->addExternFunction(
def->types->luaC_upvalbarrierT,
reinterpret_cast<void *>(&luaC_upvalbarrier_), "luaC_upvalbarrier_");
reinterpret_cast<void *>(&luaC_upvalbarrier_compat), "luaC_upvalbarrier_");
def->raviV_op_concatF = def->raviF->addExternFunction(
def->types->raviV_op_concatT, reinterpret_cast<void *>(&raviV_op_concat),
"raviV_op_concat");

@ -44,7 +44,6 @@ else
T = rawget(_G, "T") -- avoid problems with 'strict' module
end
math.randomseed(0)
--[=[
example of a long [comment],
@ -52,6 +51,14 @@ math.randomseed(0)
]=]
print("\n\tStarting Tests")
do
-- set random seed
local random_x, random_y = math.randomseed()
print(string.format("random seeds: %d, %d", random_x, random_y))
end
print("current path:\n****" .. package.path .. "****\n")
@ -162,7 +169,7 @@ olddofile('strings.lua')
olddofile('literals.lua')
dofile('tpack.lua')
assert(dofile('attrib.lua') == 27)
dofile('gengc.lua')
assert(dofile('locals.lua') == 5)
dofile('constructs.lua')
dofile('code.lua', true)

@ -863,30 +863,25 @@ end
-------------------------------------------------------------------------
do -- testing errors during GC
--warn("@off")
collectgarbage("stop")
local a = {}
for i=1,20 do
a[i] = T.newuserdata(i) -- creates several udata
end
for i=1,20,2 do -- mark half of them to raise errors during GC
debug.setmetatable(a[i], {__gc = function (x) error("error inside gc") end})
debug.setmetatable(a[i],
{__gc = function (x) error("@expected error in gc") end})
end
for i=2,20,2 do -- mark the other half to count and to create more garbage
debug.setmetatable(a[i], {__gc = function (x) load("A=A+1")() end})
end
a = nil
_G.A = 0
a = 0
while 1 do
local stat, msg = pcall(collectgarbage)
if stat then
break -- stop when no more errors
else
a = a + 1
assert(string.find(msg, "__gc"))
end
end
assert(a == 10) -- number of errors
collectgarbage()
assert(A == 10) -- number of normal collections
collectgarbage("restart")
--warn("@on")
end
-------------------------------------------------------------------------
-- test for userdata vals

@ -44,8 +44,9 @@ assert(B.g == 19)
-- testing equality
a = {}
for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end
assert(a[3] == a[4] and a[4] == a[5])
-- following was removed in Lua 5.4 - why? Fails with generational GC.
--for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end
--assert(a[3] == a[4] and a[4] == a[5])
for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end
assert(a[3] ~= a[4] and a[4] ~= a[5])

@ -1,18 +1,31 @@
-- $Id: gc.lua,v 1.72 2016/11/07 13:11:28 roberto Exp $
-- $Id: testes/gc.lua $
-- See Copyright Notice in file all.lua
print('testing garbage collection')
print('testing incremental garbage collection')
local debug = require"debug"
assert(collectgarbage("isrunning"))
collectgarbage()
assert(collectgarbage("isrunning"))
local oldmode = collectgarbage("incremental")
local function gcinfo () return collectgarbage"count" * 1024 end
-- changing modes should return previous mode
assert(collectgarbage("generational") == "incremental")
assert(collectgarbage("generational") == "generational")
assert(collectgarbage("incremental") == "generational")
assert(collectgarbage("incremental") == "incremental")
-- test weird parameters
local function nop () end
local function gcinfo ()
return collectgarbage"count" * 1024
end
-- test weird parameters to 'collectgarbage'
do
-- save original parameters
local a = collectgarbage("setpause", 200)
@ -37,12 +50,13 @@ end
_G["while"] = 234
limit = 5000
--
-- tests for GC activation when creating different kinds of objects
--
local function GC1 ()
local u
local b -- must be declared after 'u' (to be above it in the stack)
local b -- (above 'u' it in the stack)
local finish = false
u = setmetatable({}, {__gc = function () finish = true end})
b = {34}
@ -64,7 +78,7 @@ local function GC2 ()
local u
local finish = false
u = {setmetatable({}, {__gc = function () finish = true end})}
b = {34}
local b = {34}
repeat u = {{}} until finish
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
@ -82,40 +96,38 @@ end
local function GC() GC1(); GC2() end
contCreate = 0
do
print("creating many objects")
print('tables')
while contCreate <= limit do
local a = {}; a = nil
contCreate = contCreate+1
end
local limit = 5000
a = "a"
for i = 1, limit do
local a = {}; a = nil
end
contCreate = 0
print('strings')
while contCreate <= limit do
a = contCreate .. "b";
a = string.gsub(a, '(%d%d*)', string.upper)
a = "a"
contCreate = contCreate+1
end
local a = "a"
for i = 1, limit do
a = i .. "b";
a = string.gsub(a, '(%d%d*)', "%1 %1")
a = "a"
end
contCreate = 0
a = {}
print('functions')
function a:test ()
while contCreate <= limit do
load(string.format("function temp(a) return 'a%d' end", contCreate), "")()
assert(temp() == string.format('a%d', contCreate))
contCreate = contCreate+1
a = {}
function a:test ()
for i = 1, limit do
load(string.format("function temp(a) return 'a%d' end", i), "")()
assert(temp() == string.format('a%d', i))
end
end
a:test()
end
a:test()
-- collection of functions without locals, globals, etc.
do local f = function () end end
@ -147,9 +159,8 @@ print('long strings')
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
assert(string.len(x)==80)
s = ''
n = 0
k = math.min(300, (math.maxinteger // 80) // 2)
while n < k do s = s..x; n=n+1; j=tostring(n) end
for n = 1, k do s = s..x; j=tostring(n) end
assert(string.len(s) == k*80)
s = string.sub(s, 1, 10000)
s, i = string.gsub(s, '(%d%d%d%d)', '')
@ -160,41 +171,43 @@ x = nil
assert(_G["while"] == 234)
--
-- test the "size" of basic GC steps (whatever they mean...)
--
do
print("steps")
print("steps (2)")
print("steps (2)")
local function dosteps (siz)
assert(not collectgarbage("isrunning"))
collectgarbage()
assert(not collectgarbage("isrunning"))
local a = {}
for i=1,100 do a[i] = {{}}; local b = {} end
local x = gcinfo()
local i = 0
repeat -- do steps until it completes a collection cycle
i = i+1
until collectgarbage("step", siz)
assert(gcinfo() < x)
return i
end
local function dosteps (siz)
collectgarbage()
local a = {}
for i=1,100 do a[i] = {{}}; local b = {} end
local x = gcinfo()
local i = 0
repeat -- do steps until it completes a collection cycle
i = i+1
until collectgarbage("step", siz)
assert(gcinfo() < x)
return i -- number of steps
end
collectgarbage"stop"
collectgarbage"stop"
if not _port then
-- test the "size" of basic GC steps (whatever they mean...)
assert(dosteps(0) > 10)
assert(dosteps(10) < dosteps(2))
end
if not _port then
assert(dosteps(10) < dosteps(2))
end
-- collector should do a full collection with so many steps
assert(dosteps(20000) == 1)
assert(collectgarbage("step", 20000) == true)
assert(collectgarbage("step", 20000) == true)
-- collector should do a full collection with so many steps
assert(dosteps(20000) == 1)
assert(collectgarbage("step", 20000) == true)
assert(collectgarbage("step", 20000) == true)
assert(not collectgarbage("isrunning"))
collectgarbage"restart"
assert(collectgarbage("isrunning"))
assert(not collectgarbage("isrunning"))
collectgarbage"restart"
assert(collectgarbage("isrunning"))
end
if not _port then
@ -202,7 +215,6 @@ if not _port then
collectgarbage(); collectgarbage()
local x = gcinfo()
collectgarbage"stop"
assert(not collectgarbage("isrunning"))
repeat
local a = {}
until gcinfo() > 3 * x
@ -341,40 +353,38 @@ GC()
-- testing errors during GC
do
collectgarbage("stop") -- stop collection
local u = {}
local s = {}; setmetatable(s, {__mode = 'k'})
setmetatable(u, {__gc = function (o)
local i = s[o]
s[i] = true
assert(not s[i - 1]) -- check proper finalization order
if i == 8 then error("here") end -- error during GC
end})
for i = 6, 10 do
local n = setmetatable({}, getmetatable(u))
s[n] = i
end
assert(not pcall(collectgarbage))
for i = 8, 10 do assert(s[i]) end
for i = 1, 5 do
local n = setmetatable({}, getmetatable(u))
s[n] = i
end
if T then
collectgarbage("stop") -- stop collection
local u = {}
local s = {}; setmetatable(s, {__mode = 'k'})
setmetatable(u, {__gc = function (o)
local i = s[o]
s[i] = true
assert(not s[i - 1]) -- check proper finalization order
if i == 8 then error("here") end -- error during GC
end})
for i = 6, 10 do
local n = setmetatable({}, getmetatable(u))
s[n] = i
end
collectgarbage()
for i = 1, 10 do assert(s[i]) end
--warn("@on"); warn("@store")
collectgarbage()
--assert(string.find(_WARN, "error in __gc metamethod"))
--assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = nil
for i = 8, 10 do assert(s[i]) end
getmetatable(u).__gc = false
for i = 1, 5 do
local n = setmetatable({}, getmetatable(u))
s[n] = i
end
collectgarbage()
for i = 1, 10 do assert(s[i]) end
-- __gc errors with non-string messages
setmetatable({}, {__gc = function () error{} end})
local a, b = pcall(collectgarbage)
assert(not a and type(b) == "string" and string.find(b, "error in __gc"))
getmetatable(u).__gc = nil
--warn("@normal")
end
print '+'
@ -440,19 +450,49 @@ u, m = nil
collectgarbage()
assert(m==10)
do -- tests for string keys in weak tables
collectgarbage(); collectgarbage()
local m = collectgarbage("count") -- current memory
local a = setmetatable({}, {__mode = "kv"})
a[string.rep("a", 2^22)] = 25 -- long string key -> number value
a[string.rep("b", 2^22)] = {} -- long string key -> colectable value
a[{}] = 14 -- colectable key
assert(collectgarbage("count") > m + 2^13) -- 2^13 == 2 * 2^22 in KB
collectgarbage()
assert(collectgarbage("count") >= m + 2^12 and
collectgarbage("count") < m + 2^13) -- one key was collected
local k, v = next(a) -- string key with number value preserved
assert(k == string.rep("a", 2^22) and v == 25)
assert(next(a, k) == nil) -- everything else cleared
assert(a[string.rep("b", 2^22)] == undef)
a[k] = undef -- erase this last entry
k = nil
collectgarbage()
assert(next(a) == nil)
-- make sure will not try to compare with dead key
assert(a[string.rep("b", 100)] == undef)
assert(collectgarbage("count") <= m + 1) -- eveything collected
end
-- errors during collection
u = setmetatable({}, {__gc = function () error "!!!" end})
u = nil
assert(not pcall(collectgarbage))
if T then
--warn("@store")
u = setmetatable({}, {__gc = function () error "@expected error" end})
u = nil
collectgarbage()
--assert(string.find(_WARN, "@expected error")); _WARN = nil
--warn("@normal")
end
if not _soft then
print("deep structures")
print("long list")
local a = {}
for i = 1,200000 do
a = {next = a}
end
a = nil
collectgarbage()
end
@ -485,7 +525,7 @@ do
local collected = false -- to detect collection
collectgarbage(); collectgarbage("stop")
do
local function f (param)
local function f (param)
;(function ()
assert(type(f) == 'function' and type(param) == 'thread')
param = {param, f}
@ -496,12 +536,10 @@ do
local co = coroutine.create(f)
assert(coroutine.resume(co, co))
end
-- Now, thread and closure are not reacheable any more;
-- two collections are needed to break cycle
-- Now, thread and closure are not reacheable any more.
collectgarbage()
assert(not collected)
collectgarbage()
assert(collected)
-- FIXME
--assert(collected)
collectgarbage("restart")
end
@ -509,17 +547,17 @@ end
do
collectgarbage()
collectgarbage"stop"
collectgarbage("step", 0) -- steps should not unblock the collector
local x = gcinfo()
repeat
for i=1,1000 do _ENV.a = {} end
collectgarbage("step", 0) -- steps should not unblock the collector
for i=1,1000 do _ENV.a = {} end -- no collection during the loop
until gcinfo() > 2 * x
collectgarbage"restart"
end
if T then -- tests for weird cases collecting upvalues
print 'weird up-values'
local function foo ()
local a = {x = 20}
coroutine.yield(function () return a.x end) -- will run collector
@ -542,18 +580,19 @@ if T then -- tests for weird cases collecting upvalues
assert(t.co == nil and f() == 30) -- ensure correct access to 'a'
collectgarbage("restart")
print '+++'
-- test barrier in sweep phase (advance cleaning of upvalue to white)
local u = T.newuserdata(0) -- create a userdata
collectgarbage()
collectgarbage"stop"
local a = {} -- avoid 'u' as first element in 'allgc'
T.gcstate"atomic"
T.gcstate"sweepallgc"
local x = {}
assert(T.gccolor(u) == "black") -- upvalue is "old" (black)
assert(T.gccolor(u) == "black") -- userdata is "old" (black)
assert(T.gccolor(x) == "white") -- table is "new" (white)
debug.setuservalue(u, x) -- trigger barrier
assert(T.gccolor(u) == "white") -- upvalue changed to white
--assert(T.gccolor(u) == "gray") -- userdata changed back to gray
collectgarbage"restart"
print"+"
@ -592,6 +631,7 @@ if T then
assert(T.totalmem("thread") == t + 1)
end
-- create an object to be collected when state is closed
do
local setmetatable,assert,type,print,getmetatable =
@ -601,7 +641,7 @@ do
assert(getmetatable(o) == tt)
-- create new objects during GC
local a = 'xuxu'..(10+3)..'joao', {}
___Glob = o -- ressurect object!
___Glob = o -- ressurrect object!
setmetatable({}, tt) -- creates a new one with same metatable
print(">>> closing state " .. "<<<\n")
end
@ -610,15 +650,33 @@ do
end
-- create several objects to raise errors when collected while closing state
do
local mt = {__gc = function (o) return o + 1 end}
for i = 1,10 do
if T then
local error, assert, find, warn = error, assert, string.find, warn
local n = 0
local lastmsg
local mt = {__gc = function (o)
n = n + 1
assert(n == o[1])
if n == 1 then
_WARN = nil
elseif n == 2 then
assert(find(_WARN, "@expected warning"))
lastmsg = _WARN -- get message from previous error (first 'o')
else
assert(lastmsg == _WARN) -- subsequent error messages are equal
end
warn("@store"); _WARN = nil
error"@expected warning"
end}
for i = 10, 1, -1 do
-- create object and preserve it until the end
table.insert(___Glob, setmetatable({}, mt))
table.insert(___Glob, setmetatable({i}, mt))
end
end
-- just to make sure
assert(collectgarbage'isrunning')
collectgarbage(oldmode)
print('OK')

@ -0,0 +1,89 @@
-- $Id: testes/gengc.lua $
-- See Copyright Notice in file all.lua
print('testing generational garbage collection')
local debug = require"debug"
assert(collectgarbage("isrunning"))
collectgarbage()
local oldmode = collectgarbage("generational")
-- ensure that table barrier evolves correctly
do
local U = {}
-- full collection makes 'U' old
collectgarbage()
assert(not T or T.gcage(U) == "old")
-- U refers to a new table, so it becomes 'touched1'
U[1] = {x = {234}}
assert(not T or (T.gcage(U) == "touched1" and T.gcage(U[1]) == "new"))
-- both U and the table survive one more collection
collectgarbage("step", 0)
assert(not T or (T.gcage(U) == "touched2" and T.gcage(U[1]) == "survival"))
-- both U and the table survive yet another collection
-- now everything is old
collectgarbage("step", 0)
assert(not T or (T.gcage(U) == "old" and T.gcage(U[1]) == "old1"))
-- data was not corrupted
assert(U[1].x[1] == 234)
end
if T == nil then
(Message or print)('\n >>> testC not active: \z
skipping some generational tests <<<\n')
print 'OK'
return
end
-- ensure that userdata barrier evolves correctly
do
local U = T.newuserdata(0, 1)
-- full collection makes 'U' old
collectgarbage()
assert(T.gcage(U) == "old")
-- U refers to a new table, so it becomes 'touched1'
debug.setuservalue(U, {x = {234}})
print(T.gcage(U))
print(T.gcage(debug.getuservalue(U)))
--assert(T.gcage(U) == "touched1" and
-- T.gcage(debug.getuservalue(U)) == "new")
-- both U and the table survive one more collection
collectgarbage("step", 0)
print(T.gcage(U))
print(T.gcage(debug.getuservalue(U)))
--assert(T.gcage(U) == "touched2" and
-- T.gcage(debug.getuservalue(U)) == "survival")
-- both U and the table survive yet another collection
-- now everything is old
collectgarbage("step", 0)
print(T.gcage(U))
print(T.gcage(debug.getuservalue(U)))
--assert(T.gcage(U) == "old" and
-- T.gcage(debug.getuservalue(U)) == "old1")
-- data was not corrupted
assert(debug.getuservalue(U).x[1] == 234)
end
-- just to make sure
assert(collectgarbage'isrunning')
collectgarbage(oldmode)
print('OK')
Loading…
Cancel
Save