summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2019-07-12 05:23:52 -0500
committerWilliam Wilgus <me.theuser@yahoo.com>2019-07-28 15:17:48 +0200
commit45bd14b392622cb58e967a24e4652c510b3d43e4 (patch)
tree22bd2e5cafc2d82ecc4773f83de7f86515b4db43
parent4beafe16fafc2e5c59734ef065a6f8d23766520d (diff)
downloadrockbox-45bd14b.tar.gz
rockbox-45bd14b.tar.bz2
rockbox-45bd14b.zip
Lua Add Emergency Garbage Collector
Derivative of work by RobertGabrielJakabosky http://lua-users.org/wiki/EmergencyGarbageCollector I've only implemented the not enough memory part and expanded this idea to adding a mechanism to signal the OOM condition of the plugin buffer which allows us to only grab the playback buffer after garbage collection fails (SO THE MUSIC KEEPS PLAYING AS LONG AS POSSIBLE) Change-Id: I684fb98b540ffc01f7ba324ab5b761ceb59b9f9b
-rw-r--r--apps/plugins/lua/SOURCES1
-rw-r--r--apps/plugins/lua/lapi.c22
-rw-r--r--apps/plugins/lua/lauxlib.c30
-rw-r--r--apps/plugins/lua/ldo.c21
-rw-r--r--apps/plugins/lua/lfunc.c2
-rw-r--r--apps/plugins/lua/lgc.c60
-rw-r--r--apps/plugins/lua/lgc.h24
-rw-r--r--apps/plugins/lua/lobject.h36
-rw-r--r--apps/plugins/lua/lparser.c6
-rw-r--r--apps/plugins/lua/lstate.c7
-rw-r--r--apps/plugins/lua/lstate.h1
-rw-r--r--apps/plugins/lua/lstring.c28
-rw-r--r--apps/plugins/lua/ltable.c3
-rw-r--r--apps/plugins/lua/lua_user.c18
-rw-r--r--apps/plugins/lua/lua_user.h14
-rw-r--r--apps/plugins/lua/luaconf.h6
-rw-r--r--apps/plugins/lua/lvm.c42
-rw-r--r--apps/plugins/lua/lzio.h2
-rw-r--r--apps/plugins/lua/rockconf.h1
-rw-r--r--apps/plugins/lua/rocklib.c6
-rw-r--r--apps/plugins/lua/tlsf_helper.c4
21 files changed, 266 insertions, 68 deletions
diff --git a/apps/plugins/lua/SOURCES b/apps/plugins/lua/SOURCES
index 93fa5e9c83..481bf7672f 100644
--- a/apps/plugins/lua/SOURCES
+++ b/apps/plugins/lua/SOURCES
@@ -24,6 +24,7 @@ ltable.c
ltablib.c
ltm.c
lundump.c
+lua_user.c
lvm.c
lzio.c
rockaux.c
diff --git a/apps/plugins/lua/lapi.c b/apps/plugins/lua/lapi.c
index 487d6b173a..6426cd94a9 100644
--- a/apps/plugins/lua/lapi.c
+++ b/apps/plugins/lua/lapi.c
@@ -547,7 +547,9 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
lua_lock(L);
t = index2adr(L, idx);
api_checkvalidindex(L, t);
+ fixedstack(L);
setsvalue(L, &key, luaS_new(L, k));
+ unfixedstack(L);
luaV_gettable(L, t, &key, L->top);
api_incr_top(L);
lua_unlock(L);
@@ -656,14 +658,14 @@ LUA_API void lua_settable (lua_State *L, int idx) {
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
StkId t;
- TValue key;
lua_lock(L);
api_checknelems(L, 1);
t = index2adr(L, idx);
api_checkvalidindex(L, t);
- setsvalue(L, &key, luaS_new(L, k));
- luaV_settable(L, t, &key, L->top - 1);
- L->top--; /* pop value */
+ setsvalue2s(L, L->top, luaS_new(L, k));
+ api_incr_top(L);
+ luaV_settable(L, t, L->top - 1, L->top - 2);
+ L->top -= 2; /* pop key and value */
lua_unlock(L);
}
@@ -674,7 +676,9 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
api_checknelems(L, 2);
t = index2adr(L, idx);
api_check(L, ttistable(t));
+ fixedstack(L);
setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
+ unfixedstack(L);
luaC_barriert(L, hvalue(t), L->top-1);
L->top -= 2;
lua_unlock(L);
@@ -687,7 +691,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
api_checknelems(L, 1);
o = index2adr(L, idx);
api_check(L, ttistable(o));
+ fixedstack(L);
setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
+ unfixedstack(L);
luaC_barriert(L, hvalue(o), L->top-1);
L->top--;
lua_unlock(L);
@@ -903,11 +909,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
g = G(L);
switch (what) {
case LUA_GCSTOP: {
- g->GCthreshold = MAX_LUMEM;
+ set_block_gc(L);
break;
}
case LUA_GCRESTART: {
- g->GCthreshold = g->totalbytes;
+ unset_block_gc(L);
break;
}
case LUA_GCCOLLECT: {
@@ -924,6 +930,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSTEP: {
+ if(is_block_gc(L)) {
+ res = 1; /* gc is block so we need to pretend that the collection cycle finished. */
+ break;
+ }
lu_mem a = (cast(lu_mem, data) << 10);
if (a <= g->totalbytes)
g->GCthreshold = g->totalbytes - a;
diff --git a/apps/plugins/lua/lauxlib.c b/apps/plugins/lua/lauxlib.c
index 2e4b3b1e3c..acd7e0e636 100644
--- a/apps/plugins/lua/lauxlib.c
+++ b/apps/plugins/lua/lauxlib.c
@@ -13,7 +13,6 @@
#include <string.h>
#include "lstring.h" /* ROCKLUA ADDED */
-
/* This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
** Note ** luaS_newlloc breaks this guarantee ROCKLUA ADDED
@@ -34,7 +33,9 @@
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
lua_gettop(L) + (i) + 1)
-
+#ifndef LUA_OOM
+ #define LUA_OOM(L) {}
+#endif
/*
** {======================================================
** Error-report functions
@@ -756,14 +757,30 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
- (void)ud;
- (void)osize;
+ (void) osize;
+ lua_State *L = (lua_State *)ud;
+ void *nptr;
+
if (nsize == 0) {
free(ptr);
return NULL;
}
- else
- return realloc(ptr, nsize);
+
+ nptr = realloc(ptr, nsize);
+ if (nptr == NULL) {
+ if(L != NULL)
+ {
+ luaC_fullgc(L); /* emergency full collection. */
+ nptr = realloc(ptr, nsize); /* try allocation again */
+ }
+
+ if (nptr == NULL) {
+ LUA_OOM(L); /* if defined.. signal OOM condition */
+ nptr = realloc(ptr, nsize); /* try allocation again */
+ }
+ }
+
+ return nptr;
}
@@ -779,6 +796,7 @@ static int panic (lua_State *L) {
LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL);
+ lua_setallocf(L, l_alloc, L); /* allocator needs lua_State. */
if (L) lua_atpanic(L, &panic);
return L;
}
diff --git a/apps/plugins/lua/ldo.c b/apps/plugins/lua/ldo.c
index 43266de95e..7eccc54480 100644
--- a/apps/plugins/lua/ldo.c
+++ b/apps/plugins/lua/ldo.c
@@ -51,11 +51,13 @@ struct lua_longjmp {
void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
switch (errcode) {
case LUA_ERRMEM: {
- setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
+ ptrdiff_t oldtopr = savestack(L, oldtop);
+ setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, MEMERRMSG));
break;
}
case LUA_ERRERR: {
- setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
+ ptrdiff_t oldtopr = savestack(L, oldtop);
+ setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, "error in error handling"));
break;
}
case LUA_ERRSYNTAX:
@@ -92,6 +94,8 @@ static void resetstack (lua_State *L, int status) {
void luaD_throw (lua_State *L, int errcode) {
+ unfixedstack(L); /* make sure the fixedstack & block_gc flags get reset. */
+ unset_block_gc(L);
if (L->errorJmp) {
L->errorJmp->status = errcode;
LUAI_THROW(L, L->errorJmp);
@@ -208,7 +212,9 @@ void luaD_callhook (lua_State *L, int event, int line) {
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
+#if defined(LUA_COMPAT_VARARG)
Table *htab = NULL;
+#endif
StkId base, fixed;
for (; actual < nfixargs; ++actual)
setnilvalue(L->top++);
@@ -219,10 +225,15 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
luaC_checkGC(L);
luaD_checkstack(L, p->maxstacksize);
htab = luaH_new(L, nvar, 1); /* create `arg' table */
+ sethvalue2s(L, L->top, htab); /* put table on stack */
+ incr_top(L);
+ fixedstack(L);
for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
- setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
+ setobj2n(L, luaH_setnum(L, htab, i+1), L->top - 1 - nvar + i);
+ unfixedstack(L);
/* store counter in field `n' */
setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
+ L->top--; /* remove table from stack */
}
#endif
/* move fixed parameters to final position */
@@ -232,11 +243,13 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
setobjs2s(L, L->top++, fixed+i);
setnilvalue(fixed+i);
}
+#if defined(LUA_COMPAT_VARARG)
/* add `arg' parameter */
if (htab) {
sethvalue(L, L->top++, htab);
lua_assert(iswhite(obj2gco(htab)));
}
+#endif
return base;
}
@@ -495,6 +508,7 @@ static void f_parser (lua_State *L, void *ud) {
struct SParser *p = cast(struct SParser *, ud);
int c = luaZ_lookahead(p->z);
luaC_checkGC(L);
+ set_block_gc(L); /* stop collector during parsing */
tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
&p->buff, p->name);
cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
@@ -503,6 +517,7 @@ static void f_parser (lua_State *L, void *ud) {
cl->l.upvals[i] = luaF_newupval(L);
setclvalue(L, L->top, cl);
incr_top(L);
+ unset_block_gc(L);
}
diff --git a/apps/plugins/lua/lfunc.c b/apps/plugins/lua/lfunc.c
index 813e88f583..d2ce63dc4b 100644
--- a/apps/plugins/lua/lfunc.c
+++ b/apps/plugins/lua/lfunc.c
@@ -66,7 +66,6 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
}
uv = luaM_new(L, UpVal); /* not found: create a new one */
uv->tt = LUA_TUPVAL;
- uv->marked = luaC_white(g);
uv->v = level; /* current value lives in the stack */
uv->next = *pp; /* chain it in the proper position */
*pp = obj2gco(uv);
@@ -74,6 +73,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
uv->u.l.next = g->uvhead.u.l.next;
uv->u.l.next->u.l.prev = uv;
g->uvhead.u.l.next = uv;
+ luaC_marknew(L, obj2gco(uv));
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
return uv;
}
diff --git a/apps/plugins/lua/lgc.c b/apps/plugins/lua/lgc.c
index 98194c1771..17b64a103b 100644
--- a/apps/plugins/lua/lgc.c
+++ b/apps/plugins/lua/lgc.c
@@ -58,6 +58,9 @@
#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
+#ifndef yield
+ #define yield() {}
+#endif
static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n)));
@@ -232,8 +235,10 @@ static void traverseclosure (global_State *g, Closure *cl) {
int i;
lua_assert(cl->l.nupvalues == cl->l.p->nups);
markobject(g, cl->l.p);
- for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
- markobject(g, cl->l.upvals[i]);
+ for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
+ if(cl->l.upvals[i])
+ markobject(g, cl->l.upvals[i]);
+ }
}
}
@@ -258,6 +263,7 @@ static void traversestack (global_State *g, lua_State *l) {
CallInfo *ci;
markvalue(g, gt(l));
lim = l->top;
+ if(l->stack == NULL) return; /* no stack to traverse */
for (ci = l->base_ci; ci <= l->ci; ci++) {
lua_assert(ci->top <= l->stack_last);
if (lim < ci->top) lim = ci->top;
@@ -266,7 +272,8 @@ static void traversestack (global_State *g, lua_State *l) {
markvalue(g, o);
for (; o <= lim; o++)
setnilvalue(o);
- checkstacksizes(l, lim);
+ if (!isfixedstack(l)) /* if stack size is fixed, can't resize it. */
+ checkstacksizes(l, lim);
}
@@ -419,8 +426,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
else { /* must erase `curr' */
lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
*p = curr->gch.next;
- if (curr == g->rootgc) /* is the first element of the list? */
- g->rootgc = curr->gch.next; /* adjust first */
freeobj(L, curr);
}
}
@@ -434,6 +439,8 @@ static void checkSizes (lua_State *L) {
if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
g->strt.size > MINSTRTABSIZE*2)
luaS_resize(L, g->strt.size/2); /* table is too big */
+ /* it is not safe to re-size the buffer if it is in use. */
+ if (luaZ_bufflen(&g->buff) > 0) return;
/* check size of buffer */
if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
@@ -552,6 +559,15 @@ static void atomic (lua_State *L) {
g->estimate = g->totalbytes - udsize; /* first estimate */
}
+static void sweepstrstep (global_State *g, lua_State *L) {
+ lu_mem old = g->totalbytes;
+ sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
+ if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
+ g->gcstate = GCSsweep; /* end sweep-string phase */
+ lua_assert(old >= g->totalbytes);
+ g->estimate -= old - g->totalbytes;
+}
+
static l_mem singlestep (lua_State *L) {
global_State *g = G(L);
@@ -570,12 +586,7 @@ static l_mem singlestep (lua_State *L) {
}
}
case GCSsweepstring: {
- lu_mem old = g->totalbytes;
- sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
- if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
- g->gcstate = GCSsweep; /* end sweep-string phase */
- lua_assert(old >= g->totalbytes);
- g->estimate -= old - g->totalbytes;
+ sweepstrstep(g, L);
return GCSWEEPCOST;
}
case GCSsweep: {
@@ -609,10 +620,14 @@ static l_mem singlestep (lua_State *L) {
void luaC_step (lua_State *L) {
global_State *g = G(L);
+ if(is_block_gc(L)) return;
+ set_block_gc(L);
l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
if (lim == 0)
lim = (MAX_LUMEM-1)/2; /* no limit */
g->gcdept += g->totalbytes - g->GCthreshold;
+ if (g->estimate > g->totalbytes)
+ g->estimate = g->totalbytes;
do {
lim -= singlestep(L);
if (g->gcstate == GCSpause)
@@ -629,11 +644,23 @@ void luaC_step (lua_State *L) {
else {
setthreshold(g);
}
+ unset_block_gc(L);
}
+int luaC_sweepstrgc (lua_State *L) {
+ global_State *g = G(L);
+ if (g->gcstate == GCSsweepstring) {
+ sweepstrstep(g, L);
+ return (g->gcstate == GCSsweepstring) ? 1 : 0;
+ }
+ return 0;
+}
+
void luaC_fullgc (lua_State *L) {
global_State *g = G(L);
+ if(is_block_gc(L)) return;
+ set_block_gc(L);
if (g->gcstate <= GCSpropagate) {
/* reset sweep marks to sweep all elements (returning them to white) */
g->sweepstrgc = 0;
@@ -649,12 +676,15 @@ void luaC_fullgc (lua_State *L) {
while (g->gcstate != GCSfinalize) {
lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
singlestep(L);
+ yield();
}
markroot(L);
while (g->gcstate != GCSpause) {
singlestep(L);
+ yield();
}
setthreshold(g);
+ unset_block_gc(L);
}
@@ -682,6 +712,14 @@ void luaC_barrierback (lua_State *L, Table *t) {
}
+void luaC_marknew (lua_State *L, GCObject *o) {
+ global_State *g = G(L);
+ o->gch.marked = luaC_white(g);
+ if (g->gcstate == GCSpropagate)
+ reallymarkobject(g, o); /* mark new objects as gray during propagate state. */
+}
+
+
void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
global_State *g = G(L);
o->gch.next = g->rootgc;
diff --git a/apps/plugins/lua/lgc.h b/apps/plugins/lua/lgc.h
index 5123ccb479..115008d6be 100644
--- a/apps/plugins/lua/lgc.h
+++ b/apps/plugins/lua/lgc.h
@@ -37,12 +37,30 @@
#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2)))
+/*
+** Possible Garbage Collector flags.
+** Layout for bit use in 'gsflags' field in global_State structure.
+** bit 0 - Protect GC from recursive calls.
+** bit 1 - Don't try to shrink string table if EGC was called during a string table resize.
+*/
+#define GCFlagsNone 0
+#define GCBlockGCBit 0
+#define GCResizingStringsBit 1
+
+
+#define is_block_gc(L) testbit(G(L)->gcflags, GCBlockGCBit)
+#define set_block_gc(L) l_setbit(G(L)->gcflags, GCBlockGCBit)
+#define unset_block_gc(L) resetbit(G(L)->gcflags, GCBlockGCBit)
+#define is_resizing_strings_gc(L) testbit(G(L)->gcflags, GCResizingStringsBit)
+#define set_resizing_strings_gc(L) l_setbit(G(L)->gcflags, GCResizingStringsBit)
+#define unset_resizing_strings_gc(L) resetbit(G(L)->gcflags, GCResizingStringsBit)
/*
** Layout for bit use in `marked' field:
** bit 0 - object is white (type 0)
** bit 1 - object is white (type 1)
** bit 2 - object is black
+** bit 3 - for thread: Don't resize thread's stack
** bit 3 - for userdata: has been finalized
** bit 3 - for tables: has weak keys
** bit 4 - for tables: has weak values
@@ -54,6 +72,7 @@
#define WHITE0BIT 0
#define WHITE1BIT 1
#define BLACKBIT 2
+#define FIXEDSTACKBIT 3
#define FINALIZEDBIT 3
#define KEYWEAKBIT 3
#define VALUEWEAKBIT 4
@@ -76,6 +95,9 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
+#define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT)
+#define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT)
+#define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT)
#define luaC_checkGC(L) { \
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
@@ -101,6 +123,8 @@ LUAI_FUNC void luaC_callGCTM (lua_State *L);
LUAI_FUNC void luaC_freeall (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_fullgc (lua_State *L);
+LUAI_FUNC int luaC_sweepstrgc (lua_State *L);
+LUAI_FUNC void luaC_marknew (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
diff --git a/apps/plugins/lua/lobject.h b/apps/plugins/lua/lobject.h
index 26d2a81b49..028ff0355b 100644
--- a/apps/plugins/lua/lobject.h
+++ b/apps/plugins/lua/lobject.h
@@ -117,42 +117,48 @@ typedef struct lua_TValue {
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
#define setnvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
+ { lua_Number i_x = (x); TValue *i_o=(obj); i_o->value.n=i_x; i_o->tt=LUA_TNUMBER; }
#define setpvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
+ { void *i_x = (x); TValue *i_o=(obj); i_o->value.p=i_x; i_o->tt=LUA_TLIGHTUSERDATA; }
#define setbvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
+ { int i_x = (x); TValue *i_o=(obj); i_o->value.b=i_x; i_o->tt=LUA_TBOOLEAN; }
#define setsvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
+ { GCObject *i_x = cast(GCObject *, (x)); \
+ TValue *i_o=(obj); \
+ i_o->value.gc=i_x; i_o->tt=LUA_TSTRING; \
checkliveness(G(L),i_o); }
#define setuvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
+ { GCObject *i_x = cast(GCObject *, (x)); \
+ TValue *i_o=(obj); \
+ i_o->value.gc=i_x; i_o->tt=LUA_TUSERDATA; \
checkliveness(G(L),i_o); }
#define setthvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
+ { GCObject *i_x = cast(GCObject *, (x)); \
+ TValue *i_o=(obj); \
+ i_o->value.gc=i_x; i_o->tt=LUA_TTHREAD; \
checkliveness(G(L),i_o); }
#define setclvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
+ { GCObject *i_x = cast(GCObject *, (x)); \
+ TValue *i_o=(obj); \
+ i_o->value.gc=i_x; i_o->tt=LUA_TFUNCTION; \
checkliveness(G(L),i_o); }
#define sethvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
+ { GCObject *i_x = cast(GCObject *, (x)); \
+ TValue *i_o=(obj); \
+ i_o->value.gc=i_x; i_o->tt=LUA_TTABLE; \
checkliveness(G(L),i_o); }
#define setptvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
+ { GCObject *i_x = cast(GCObject *, (x)); \
+ TValue *i_o=(obj); \
+ i_o->value.gc=i_x; i_o->tt=LUA_TPROTO; \
checkliveness(G(L),i_o); }
diff --git a/apps/plugins/lua/lparser.c b/apps/plugins/lua/lparser.c
index dda7488dca..d002e96b86 100644
--- a/apps/plugins/lua/lparser.c
+++ b/apps/plugins/lua/lparser.c
@@ -383,14 +383,18 @@ static void close_func (LexState *ls) {
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
struct LexState lexstate;
struct FuncState funcstate;
+ TString *tname = luaS_new(L, name);
+ setsvalue2s(L, L->top, tname); /* protect name */
+ incr_top(L);
lexstate.buff = buff;
- luaX_setinput(L, &lexstate, z, luaS_new(L, name));
+ luaX_setinput(L, &lexstate, z, tname);
open_func(&lexstate, &funcstate);
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
luaX_next(&lexstate); /* read first token */
chunk(&lexstate);
check(&lexstate, TK_EOS);
close_func(&lexstate);
+ L->top--; /* remove 'name' from stack */
lua_assert(funcstate.prev == NULL);
lua_assert(funcstate.f->nups == 0);
lua_assert(lexstate.fs == NULL);
diff --git a/apps/plugins/lua/lstate.c b/apps/plugins/lua/lstate.c
index 4313b83a0c..67921d84a1 100644
--- a/apps/plugins/lua/lstate.c
+++ b/apps/plugins/lua/lstate.c
@@ -119,6 +119,8 @@ static void close_state (lua_State *L) {
lua_State *luaE_newthread (lua_State *L) {
lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
luaC_link(L, obj2gco(L1), LUA_TTHREAD);
+ setthvalue(L, L->top, L1); /* put thread on stack */
+ incr_top(L);
preinit_state(L1, G(L));
stack_init(L1, L); /* init stack */
setobj2n(L, gt(L1), gt(L)); /* share table of globals */
@@ -126,7 +128,8 @@ lua_State *luaE_newthread (lua_State *L) {
L1->basehookcount = L->basehookcount;
L1->hook = L->hook;
resethookcount(L1);
- lua_assert(iswhite(obj2gco(L1)));
+ lua_assert(!isdead(G(L), obj2gco(L1)));
+ L->top--; /* remove thread from stack */
return L1;
}
@@ -160,6 +163,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->uvhead.u.l.prev = &g->uvhead;
g->uvhead.u.l.next = &g->uvhead;
g->GCthreshold = 0; /* mark it as unfinished state */
+ g->estimate = 0;
g->strt.size = 0;
g->strt.nuse = 0;
g->strt.hash = NULL;
@@ -167,6 +171,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->gcstate = GCSpause;
+ g->gcflags = GCFlagsNone;
g->rootgc = obj2gco(L);
g->sweepstrgc = 0;
g->sweepgc = &g->rootgc;
diff --git a/apps/plugins/lua/lstate.h b/apps/plugins/lua/lstate.h
index 94a6249461..82431bc5a9 100644
--- a/apps/plugins/lua/lstate.h
+++ b/apps/plugins/lua/lstate.h
@@ -71,6 +71,7 @@ typedef struct global_State {
void *ud; /* auxiliary data to `frealloc' */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
+ lu_byte gcflags; /* flags for the garbage collector */
int sweepstrgc; /* position of sweep in `strt' */
GCObject *rootgc; /* list of all collectable objects */
GCObject **sweepgc; /* position of sweep in `rootgc' */
diff --git a/apps/plugins/lua/lstring.c b/apps/plugins/lua/lstring.c
index bf0536e311..6d73f1e9ea 100644
--- a/apps/plugins/lua/lstring.c
+++ b/apps/plugins/lua/lstring.c
@@ -22,30 +22,34 @@
void luaS_resize (lua_State *L, int newsize) {
- GCObject **newhash;
stringtable *tb;
int i;
- if (G(L)->gcstate == GCSsweepstring)
- return; /* cannot resize during GC traverse */
- newhash = luaM_newvector(L, newsize, GCObject *);
tb = &G(L)->strt;
- for (i=0; i<newsize; i++) newhash[i] = NULL;
+ if (luaC_sweepstrgc(L) || newsize == tb->size || is_resizing_strings_gc(L))
+ return; /* cannot resize during GC traverse or doesn't need to be resized */
+ set_resizing_strings_gc(L);
+ if (newsize > tb->size) {
+ luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
+ for (i=tb->size; i<newsize; i++) tb->hash[i] = NULL;
+ }
/* rehash */
for (i=0; i<tb->size; i++) {
GCObject *p = tb->hash[i];
+ tb->hash[i] = NULL;
while (p) { /* for each node in the list */
GCObject *next = p->gch.next; /* save next */
unsigned int h = gco2ts(p)->hash;
int h1 = lmod(h, newsize); /* new position */
lua_assert(cast_int(h%newsize) == lmod(h, newsize));
- p->gch.next = newhash[h1]; /* chain it */
- newhash[h1] = p;
+ p->gch.next = tb->hash[h1]; /* chain it */
+ tb->hash[h1] = p;
p = next;
}
}
- luaM_freearray(L, tb->hash, tb->size, TString *);
+ if (newsize < tb->size)
+ luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
tb->size = newsize;
- tb->hash = newhash;
+ unset_resizing_strings_gc(L);
}
@@ -55,6 +59,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
stringtable *tb;
if (l > ((MAX_SIZET - sizeof(TString))/sizeof(char)) - sizeof(""))
luaM_toobig(L);
+ tb = &G(L)->strt;
+ if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
+ luaS_resize(L, tb->size*2); /* too crowded */
ts = cast(TString *, luaM_malloc(L, sizetstring(type, l)));
ts->tsv.len = l;
ts->tsv.hash = h;
@@ -70,13 +77,10 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
memcpy(ts+1, str, l*sizeof(char));
((char *)(ts+1))[l] = '\0'; /* ending 0 */
}
- tb = &G(L)->strt;
h = lmod(h, tb->size);
ts->tsv.next = tb->hash[h]; /* chain new entry */
tb->hash[h] = obj2gco(ts);
tb->nuse++;
- if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
- luaS_resize(L, tb->size*2); /* too crowded */
return ts;
}
diff --git a/apps/plugins/lua/ltable.c b/apps/plugins/lua/ltable.c
index ec84f4fabc..31162fe7c1 100644
--- a/apps/plugins/lua/ltable.c
+++ b/apps/plugins/lua/ltable.c
@@ -358,6 +358,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
Table *luaH_new (lua_State *L, int narray, int nhash) {
Table *t = luaM_new(L, Table);
luaC_link(L, obj2gco(t), LUA_TTABLE);
+ sethvalue2s(L, L->top, t); /* put table on stack */
+ incr_top(L);
t->metatable = NULL;
t->flags = cast_byte(~0);
/* temporary values (kept only if some malloc fails) */
@@ -367,6 +369,7 @@ Table *luaH_new (lua_State *L, int narray, int nhash) {
t->node = cast(Node *, dummynode);
setarrayvector(L, t, narray);
setnodevector(L, t, nhash);
+ L->top--; /* remove table from stack */
return t;
}
diff --git a/apps/plugins/lua/lua_user.c b/apps/plugins/lua/lua_user.c
new file mode 100644
index 0000000000..8d77dcdf3f
--- /dev/null
+++ b/apps/plugins/lua/lua_user.c
@@ -0,0 +1,18 @@
+#include "plugin.h"
+#include "lstate.h"
+#include LUA_USER_H
+
+/* lua Out Of Memory */
+static struct lua_OOM l_oom = {NULL, 0};
+
+int set_lua_OOM(lua_State * L)
+{
+ l_oom.L = L;
+ l_oom.count++;
+ return 0;
+}
+
+struct lua_OOM *get_lua_OOM(void)
+{
+ return &l_oom;
+}
diff --git a/apps/plugins/lua/lua_user.h b/apps/plugins/lua/lua_user.h
new file mode 100644
index 0000000000..f18f5e9d14
--- /dev/null
+++ b/apps/plugins/lua/lua_user.h
@@ -0,0 +1,14 @@
+#ifndef _LUA_USER_H_
+#define _LUA_USER_H_
+
+#define LUA_OOM(L) set_lua_OOM(L)
+
+struct lua_OOM {
+ lua_State * L;
+ int count;
+};
+
+int set_lua_OOM(lua_State * L);
+
+struct lua_OOM* get_lua_OOM(void);
+#endif
diff --git a/apps/plugins/lua/luaconf.h b/apps/plugins/lua/luaconf.h
index 582968d423..62a3ea0f6b 100644
--- a/apps/plugins/lua/luaconf.h
+++ b/apps/plugins/lua/luaconf.h
@@ -810,7 +810,13 @@ extern long rb_pow(long, long);
/*Rocklua functions*/
#include "rockconf.h"
+/* heap */
+#undef LUAI_GCPAUSE /*200*/
+#define LUAI_GCPAUSE 125
+#define MINSTRTABSIZE 512 /*32*/
+
/*else*/
+#define LUA_USER_H "lua_user.h"
#define LUA_DISABLE_BYTECODE
#endif
diff --git a/apps/plugins/lua/lvm.c b/apps/plugins/lua/lvm.c
index 35a931d7a1..4979b6a88e 100644
--- a/apps/plugins/lua/lvm.c
+++ b/apps/plugins/lua/lvm.c
@@ -49,9 +49,10 @@ int luaV_tostring (lua_State *L, StkId obj) {
return 0;
else {
char s[LUAI_MAXNUMBER2STR];
+ ptrdiff_t objr = savestack(L, obj);
lua_Number n = nvalue(obj);
lua_number2str(s, n);
- setsvalue2s(L, obj, luaS_new(L, s));
+ setsvalue2s(L, restorestack(L, objr), luaS_new(L, s));
return 1;
}
}
@@ -134,6 +135,9 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop;
TValue temp;
+ setnilvalue(L->top);
+ L->top++;
+ fixedstack(L);
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */
@@ -141,6 +145,8 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
if (!ttisnil(oldval) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
+ L->top--;
+ unfixedstack(L);
setobj2t(L, oldval, val);
h->flags = 0;
luaC_barriert(L, h, val);
@@ -151,12 +157,15 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm)) {
+ L->top--;
+ unfixedstack(L);
callTM(L, tm, t, key, val);
return;
}
/* else repeat with `tm' */
setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */
t = &temp;
+ setobj2s(L, L->top-1, t); /* need to protect value from EGC. */
}
luaG_runerror(L, "loop in settable");
}
@@ -284,8 +293,11 @@ void luaV_concat (lua_State *L, int total, int last) {
StkId top = L->base + last + 1;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
- if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
+ if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) {
+ /* restore 'top' pointer, since stack might have been reallocted */
+ top = L->base + last + 1;
luaG_concaterror(L, top-2, top-1);
+ }
} else if (tsvalue(top-1)->len == 0) /* second op is empty? */
(void)tostring(L, top - 2); /* result is first op (as string) */
else {
@@ -293,12 +305,14 @@ void luaV_concat (lua_State *L, int total, int last) {
size_t tl = tsvalue(top-1)->len;
char *buffer;
int i;
+ fixedstack(L);
/* collect total length */
for (n = 1; n < total && tostring(L, top-n-1); n++) {
size_t l = tsvalue(top-n-1)->len;
if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
tl += l;
}
+ G(L)->buff.n = tl;
buffer = luaZ_openspace(L, &G(L)->buff, tl);
tl = 0;
for (i=n; i>0; i--) { /* concat all strings */
@@ -307,6 +321,8 @@ void luaV_concat (lua_State *L, int total, int last) {
tl += l;
}
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
+ luaZ_resetbuffer(&G(L)->buff);
+ unfixedstack(L);
}
total -= n-1; /* got `n' strings to create 1 new */
last -= n-1;
@@ -332,8 +348,13 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
default: lua_assert(0); break;
}
}
- else if (!call_binTM(L, rb, rc, ra, op))
- luaG_aritherror(L, rb, rc);
+ else {
+ ptrdiff_t br = savestack(L, rb);
+ ptrdiff_t cr = savestack(L, rc);
+ if (!call_binTM(L, rb, rc, ra, op)) {
+ luaG_aritherror(L, restorestack(L, br), restorestack(L, cr));
+ }
+ }
}
@@ -461,7 +482,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
case OP_NEWTABLE: {
int b = GETARG_B(i);
int c = GETARG_C(i);
- sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
+ Table *h;
+ Protect(h = luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
+ sethvalue(L, RA(i), h);
Protect(luaC_checkGC(L));
continue;
}
@@ -547,9 +570,10 @@ void luaV_execute (lua_State *L, int nexeccalls) {
break;
}
default: { /* try metamethod */
+ ptrdiff_t br = savestack(L, rb);
Protect(
if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
- luaG_typeerror(L, rb, "get length of");
+ luaG_typeerror(L, restorestack(L, br), "get length of");
)
}
}
@@ -723,6 +747,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
int c = GETARG_C(i);
int last;
Table *h;
+ fixedstack(L);
if (n == 0) {
n = cast_int(L->top - ra) - 1;
L->top = L->ci->top;
@@ -738,6 +763,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
setobj2t(L, luaH_setnum(L, h, last--), val);
luaC_barriert(L, h, val);
}
+ unfixedstack(L);
continue;
}
case OP_CLOSE: {
@@ -750,7 +776,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
int nup, j;
p = cl->p->p[GETARG_Bx(i)];
nup = p->nups;
+ fixedstack(L);
ncl = luaF_newLclosure(L, nup, cl->env);
+ setclvalue(L, ra, ncl);
ncl->l.p = p;
for (j=0; j<nup; j++, pc++) {
if (GET_OPCODE(*pc) == OP_GETUPVAL)
@@ -760,7 +788,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
}
}
- setclvalue(L, ra, ncl);
+ unfixedstack(L);
Protect(luaC_checkGC(L));
continue;
}
diff --git a/apps/plugins/lua/lzio.h b/apps/plugins/lua/lzio.h
index 9aa9e4b537..cb32e6abc4 100644
--- a/apps/plugins/lua/lzio.h
+++ b/apps/plugins/lua/lzio.h
@@ -27,7 +27,7 @@ typedef struct Mbuffer {
size_t buffsize;
} Mbuffer;
-#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
+#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->n = 0, (buff)->buffsize = 0)
#define luaZ_buffer(buff) ((buff)->buffer)
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
diff --git a/apps/plugins/lua/rockconf.h b/apps/plugins/lua/rockconf.h
index 89ab82e377..6a1141f86a 100644
--- a/apps/plugins/lua/rockconf.h
+++ b/apps/plugins/lua/rockconf.h
@@ -63,6 +63,7 @@ long lpow(long x, long y);
#define strcmp rb->strcmp
#define strcpy rb->strcpy
#define strlen rb->strlen
+#define yield() rb->yield()
#endif /* _ROCKCONF_H_ */
diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c
index d1ef3adaaf..c266516602 100644
--- a/apps/plugins/lua/rocklib.c
+++ b/apps/plugins/lua/rocklib.c
@@ -304,7 +304,7 @@ RB_WRAP(playlist)
break;
}
- rb->yield();
+ yield();
lua_pushinteger(L, result);
return 1;
}
@@ -382,7 +382,7 @@ RB_WRAP(audio)
return 1;
}
- rb->yield();
+ yield();
lua_pushinteger(L, status); /* return previous (or current) audio status */
return 1;
}
@@ -502,7 +502,7 @@ RB_WRAP(pcm)
break;
}
- rb->yield();
+ yield();
return 1;
}
diff --git a/apps/plugins/lua/tlsf_helper.c b/apps/plugins/lua/tlsf_helper.c
index edf32eecf9..097d39c8e4 100644
--- a/apps/plugins/lua/tlsf_helper.c
+++ b/apps/plugins/lua/tlsf_helper.c
@@ -20,6 +20,7 @@
#include "plugin.h"
#include <tlsf.h>
+#include "lua.h"
void *get_new_area(size_t *size)
{
@@ -36,7 +37,8 @@ void *get_new_area(size_t *size)
return pluginbuf_ptr;
}
- if (audiobuf_ptr == NULL)
+ /* only grab the next area if lua already tried + failed to garbage collect*/
+ if (audiobuf_ptr == NULL && (get_lua_OOM())->count > 0)
{
/* grab audiobuffer */
audiobuf_ptr = rb->plugin_get_audio_buffer(size);