summaryrefslogtreecommitdiff
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-45bd14b392622cb58e967a24e4652c510b3d43e4.tar.gz
rockbox-45bd14b392622cb58e967a24e4652c510b3d43e4.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
24ltablib.c 24ltablib.c
25ltm.c 25ltm.c
26lundump.c 26lundump.c
27lua_user.c
27lvm.c 28lvm.c
28lzio.c 29lzio.c
29rockaux.c 30rockaux.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) {
547 lua_lock(L); 547 lua_lock(L);
548 t = index2adr(L, idx); 548 t = index2adr(L, idx);
549 api_checkvalidindex(L, t); 549 api_checkvalidindex(L, t);
550 fixedstack(L);
550 setsvalue(L, &key, luaS_new(L, k)); 551 setsvalue(L, &key, luaS_new(L, k));
552 unfixedstack(L);
551 luaV_gettable(L, t, &key, L->top); 553 luaV_gettable(L, t, &key, L->top);
552 api_incr_top(L); 554 api_incr_top(L);
553 lua_unlock(L); 555 lua_unlock(L);
@@ -656,14 +658,14 @@ LUA_API void lua_settable (lua_State *L, int idx) {
656 658
657LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { 659LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
658 StkId t; 660 StkId t;
659 TValue key;
660 lua_lock(L); 661 lua_lock(L);
661 api_checknelems(L, 1); 662 api_checknelems(L, 1);
662 t = index2adr(L, idx); 663 t = index2adr(L, idx);
663 api_checkvalidindex(L, t); 664 api_checkvalidindex(L, t);
664 setsvalue(L, &key, luaS_new(L, k)); 665 setsvalue2s(L, L->top, luaS_new(L, k));
665 luaV_settable(L, t, &key, L->top - 1); 666 api_incr_top(L);
666 L->top--; /* pop value */ 667 luaV_settable(L, t, L->top - 1, L->top - 2);
668 L->top -= 2; /* pop key and value */
667 lua_unlock(L); 669 lua_unlock(L);
668} 670}
669 671
@@ -674,7 +676,9 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
674 api_checknelems(L, 2); 676 api_checknelems(L, 2);
675 t = index2adr(L, idx); 677 t = index2adr(L, idx);
676 api_check(L, ttistable(t)); 678 api_check(L, ttistable(t));
679 fixedstack(L);
677 setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); 680 setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
681 unfixedstack(L);
678 luaC_barriert(L, hvalue(t), L->top-1); 682 luaC_barriert(L, hvalue(t), L->top-1);
679 L->top -= 2; 683 L->top -= 2;
680 lua_unlock(L); 684 lua_unlock(L);
@@ -687,7 +691,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
687 api_checknelems(L, 1); 691 api_checknelems(L, 1);
688 o = index2adr(L, idx); 692 o = index2adr(L, idx);
689 api_check(L, ttistable(o)); 693 api_check(L, ttistable(o));
694 fixedstack(L);
690 setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); 695 setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
696 unfixedstack(L);
691 luaC_barriert(L, hvalue(o), L->top-1); 697 luaC_barriert(L, hvalue(o), L->top-1);
692 L->top--; 698 L->top--;
693 lua_unlock(L); 699 lua_unlock(L);
@@ -903,11 +909,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
903 g = G(L); 909 g = G(L);
904 switch (what) { 910 switch (what) {
905 case LUA_GCSTOP: { 911 case LUA_GCSTOP: {
906 g->GCthreshold = MAX_LUMEM; 912 set_block_gc(L);
907 break; 913 break;
908 } 914 }
909 case LUA_GCRESTART: { 915 case LUA_GCRESTART: {
910 g->GCthreshold = g->totalbytes; 916 unset_block_gc(L);
911 break; 917 break;
912 } 918 }
913 case LUA_GCCOLLECT: { 919 case LUA_GCCOLLECT: {
@@ -924,6 +930,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
924 break; 930 break;
925 } 931 }
926 case LUA_GCSTEP: { 932 case LUA_GCSTEP: {
933 if(is_block_gc(L)) {
934 res = 1; /* gc is block so we need to pretend that the collection cycle finished. */
935 break;
936 }
927 lu_mem a = (cast(lu_mem, data) << 10); 937 lu_mem a = (cast(lu_mem, data) << 10);
928 if (a <= g->totalbytes) 938 if (a <= g->totalbytes)
929 g->GCthreshold = g->totalbytes - a; 939 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 @@
13#include <string.h> 13#include <string.h>
14#include "lstring.h" /* ROCKLUA ADDED */ 14#include "lstring.h" /* ROCKLUA ADDED */
15 15
16
17/* This file uses only the official API of Lua. 16/* This file uses only the official API of Lua.
18** Any function declared here could be written as an application function. 17** Any function declared here could be written as an application function.
19** Note ** luaS_newlloc breaks this guarantee ROCKLUA ADDED 18** Note ** luaS_newlloc breaks this guarantee ROCKLUA ADDED
@@ -34,7 +33,9 @@
34#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ 33#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
35 lua_gettop(L) + (i) + 1) 34 lua_gettop(L) + (i) + 1)
36 35
37 36#ifndef LUA_OOM
37 #define LUA_OOM(L) {}
38#endif
38/* 39/*
39** {====================================================== 40** {======================================================
40** Error-report functions 41** Error-report functions
@@ -756,14 +757,30 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
756 757
757 758
758static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { 759static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
759 (void)ud; 760 (void) osize;
760 (void)osize; 761 lua_State *L = (lua_State *)ud;
762 void *nptr;
763
761 if (nsize == 0) { 764 if (nsize == 0) {
762 free(ptr); 765 free(ptr);
763 return NULL; 766 return NULL;
764 } 767 }
765 else 768
766 return realloc(ptr, nsize); 769 nptr = realloc(ptr, nsize);
770 if (nptr == NULL) {
771 if(L != NULL)
772 {
773 luaC_fullgc(L); /* emergency full collection. */
774 nptr = realloc(ptr, nsize); /* try allocation again */
775 }
776
777 if (nptr == NULL) {
778 LUA_OOM(L); /* if defined.. signal OOM condition */
779 nptr = realloc(ptr, nsize); /* try allocation again */
780 }
781 }
782
783 return nptr;
767} 784}
768 785
769 786
@@ -779,6 +796,7 @@ static int panic (lua_State *L) {
779 796
780LUALIB_API lua_State *luaL_newstate (void) { 797LUALIB_API lua_State *luaL_newstate (void) {
781 lua_State *L = lua_newstate(l_alloc, NULL); 798 lua_State *L = lua_newstate(l_alloc, NULL);
799 lua_setallocf(L, l_alloc, L); /* allocator needs lua_State. */
782 if (L) lua_atpanic(L, &panic); 800 if (L) lua_atpanic(L, &panic);
783 return L; 801 return L;
784} 802}
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 {
51void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { 51void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
52 switch (errcode) { 52 switch (errcode) {
53 case LUA_ERRMEM: { 53 case LUA_ERRMEM: {
54 setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); 54 ptrdiff_t oldtopr = savestack(L, oldtop);
55 setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, MEMERRMSG));
55 break; 56 break;
56 } 57 }
57 case LUA_ERRERR: { 58 case LUA_ERRERR: {
58 setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); 59 ptrdiff_t oldtopr = savestack(L, oldtop);
60 setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, "error in error handling"));
59 break; 61 break;
60 } 62 }
61 case LUA_ERRSYNTAX: 63 case LUA_ERRSYNTAX:
@@ -92,6 +94,8 @@ static void resetstack (lua_State *L, int status) {
92 94
93 95
94void luaD_throw (lua_State *L, int errcode) { 96void luaD_throw (lua_State *L, int errcode) {
97 unfixedstack(L); /* make sure the fixedstack & block_gc flags get reset. */
98 unset_block_gc(L);
95 if (L->errorJmp) { 99 if (L->errorJmp) {
96 L->errorJmp->status = errcode; 100 L->errorJmp->status = errcode;
97 LUAI_THROW(L, L->errorJmp); 101 LUAI_THROW(L, L->errorJmp);
@@ -208,7 +212,9 @@ void luaD_callhook (lua_State *L, int event, int line) {
208static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { 212static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
209 int i; 213 int i;
210 int nfixargs = p->numparams; 214 int nfixargs = p->numparams;
215#if defined(LUA_COMPAT_VARARG)
211 Table *htab = NULL; 216 Table *htab = NULL;
217#endif
212 StkId base, fixed; 218 StkId base, fixed;
213 for (; actual < nfixargs; ++actual) 219 for (; actual < nfixargs; ++actual)
214 setnilvalue(L->top++); 220 setnilvalue(L->top++);
@@ -219,10 +225,15 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
219 luaC_checkGC(L); 225 luaC_checkGC(L);
220 luaD_checkstack(L, p->maxstacksize); 226 luaD_checkstack(L, p->maxstacksize);
221 htab = luaH_new(L, nvar, 1); /* create `arg' table */ 227 htab = luaH_new(L, nvar, 1); /* create `arg' table */
228 sethvalue2s(L, L->top, htab); /* put table on stack */
229 incr_top(L);
230 fixedstack(L);
222 for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */ 231 for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
223 setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i); 232 setobj2n(L, luaH_setnum(L, htab, i+1), L->top - 1 - nvar + i);
233 unfixedstack(L);
224 /* store counter in field `n' */ 234 /* store counter in field `n' */
225 setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); 235 setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
236 L->top--; /* remove table from stack */
226 } 237 }
227#endif 238#endif
228 /* move fixed parameters to final position */ 239 /* move fixed parameters to final position */
@@ -232,11 +243,13 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
232 setobjs2s(L, L->top++, fixed+i); 243 setobjs2s(L, L->top++, fixed+i);
233 setnilvalue(fixed+i); 244 setnilvalue(fixed+i);
234 } 245 }
246#if defined(LUA_COMPAT_VARARG)
235 /* add `arg' parameter */ 247 /* add `arg' parameter */
236 if (htab) { 248 if (htab) {
237 sethvalue(L, L->top++, htab); 249 sethvalue(L, L->top++, htab);
238 lua_assert(iswhite(obj2gco(htab))); 250 lua_assert(iswhite(obj2gco(htab)));
239 } 251 }
252#endif
240 return base; 253 return base;
241} 254}
242 255
@@ -495,6 +508,7 @@ static void f_parser (lua_State *L, void *ud) {
495 struct SParser *p = cast(struct SParser *, ud); 508 struct SParser *p = cast(struct SParser *, ud);
496 int c = luaZ_lookahead(p->z); 509 int c = luaZ_lookahead(p->z);
497 luaC_checkGC(L); 510 luaC_checkGC(L);
511 set_block_gc(L); /* stop collector during parsing */
498 tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, 512 tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
499 &p->buff, p->name); 513 &p->buff, p->name);
500 cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); 514 cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
@@ -503,6 +517,7 @@ static void f_parser (lua_State *L, void *ud) {
503 cl->l.upvals[i] = luaF_newupval(L); 517 cl->l.upvals[i] = luaF_newupval(L);
504 setclvalue(L, L->top, cl); 518 setclvalue(L, L->top, cl);
505 incr_top(L); 519 incr_top(L);
520 unset_block_gc(L);
506} 521}
507 522
508 523
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) {
66 } 66 }
67 uv = luaM_new(L, UpVal); /* not found: create a new one */ 67 uv = luaM_new(L, UpVal); /* not found: create a new one */
68 uv->tt = LUA_TUPVAL; 68 uv->tt = LUA_TUPVAL;
69 uv->marked = luaC_white(g);
70 uv->v = level; /* current value lives in the stack */ 69 uv->v = level; /* current value lives in the stack */
71 uv->next = *pp; /* chain it in the proper position */ 70 uv->next = *pp; /* chain it in the proper position */
72 *pp = obj2gco(uv); 71 *pp = obj2gco(uv);
@@ -74,6 +73,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
74 uv->u.l.next = g->uvhead.u.l.next; 73 uv->u.l.next = g->uvhead.u.l.next;
75 uv->u.l.next->u.l.prev = uv; 74 uv->u.l.next->u.l.prev = uv;
76 g->uvhead.u.l.next = uv; 75 g->uvhead.u.l.next = uv;
76 luaC_marknew(L, obj2gco(uv));
77 lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); 77 lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
78 return uv; 78 return uv;
79} 79}
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 @@
58 58
59#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) 59#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
60 60
61#ifndef yield
62 #define yield() {}
63#endif
61 64
62static void removeentry (Node *n) { 65static void removeentry (Node *n) {
63 lua_assert(ttisnil(gval(n))); 66 lua_assert(ttisnil(gval(n)));
@@ -232,8 +235,10 @@ static void traverseclosure (global_State *g, Closure *cl) {
232 int i; 235 int i;
233 lua_assert(cl->l.nupvalues == cl->l.p->nups); 236 lua_assert(cl->l.nupvalues == cl->l.p->nups);
234 markobject(g, cl->l.p); 237 markobject(g, cl->l.p);
235 for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ 238 for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
236 markobject(g, cl->l.upvals[i]); 239 if(cl->l.upvals[i])
240 markobject(g, cl->l.upvals[i]);
241 }
237 } 242 }
238} 243}
239 244
@@ -258,6 +263,7 @@ static void traversestack (global_State *g, lua_State *l) {
258 CallInfo *ci; 263 CallInfo *ci;
259 markvalue(g, gt(l)); 264 markvalue(g, gt(l));
260 lim = l->top; 265 lim = l->top;
266 if(l->stack == NULL) return; /* no stack to traverse */
261 for (ci = l->base_ci; ci <= l->ci; ci++) { 267 for (ci = l->base_ci; ci <= l->ci; ci++) {
262 lua_assert(ci->top <= l->stack_last); 268 lua_assert(ci->top <= l->stack_last);
263 if (lim < ci->top) lim = ci->top; 269 if (lim < ci->top) lim = ci->top;
@@ -266,7 +272,8 @@ static void traversestack (global_State *g, lua_State *l) {
266 markvalue(g, o); 272 markvalue(g, o);
267 for (; o <= lim; o++) 273 for (; o <= lim; o++)
268 setnilvalue(o); 274 setnilvalue(o);
269 checkstacksizes(l, lim); 275 if (!isfixedstack(l)) /* if stack size is fixed, can't resize it. */
276 checkstacksizes(l, lim);
270} 277}
271 278
272 279
@@ -419,8 +426,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
419 else { /* must erase `curr' */ 426 else { /* must erase `curr' */
420 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); 427 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
421 *p = curr->gch.next; 428 *p = curr->gch.next;
422 if (curr == g->rootgc) /* is the first element of the list? */
423 g->rootgc = curr->gch.next; /* adjust first */
424 freeobj(L, curr); 429 freeobj(L, curr);
425 } 430 }
426 } 431 }
@@ -434,6 +439,8 @@ static void checkSizes (lua_State *L) {
434 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && 439 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
435 g->strt.size > MINSTRTABSIZE*2) 440 g->strt.size > MINSTRTABSIZE*2)
436 luaS_resize(L, g->strt.size/2); /* table is too big */ 441 luaS_resize(L, g->strt.size/2); /* table is too big */
442 /* it is not safe to re-size the buffer if it is in use. */
443 if (luaZ_bufflen(&g->buff) > 0) return;
437 /* check size of buffer */ 444 /* check size of buffer */
438 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ 445 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
439 size_t newsize = luaZ_sizebuffer(&g->buff) / 2; 446 size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
@@ -552,6 +559,15 @@ static void atomic (lua_State *L) {
552 g->estimate = g->totalbytes - udsize; /* first estimate */ 559 g->estimate = g->totalbytes - udsize; /* first estimate */
553} 560}
554 561
562static void sweepstrstep (global_State *g, lua_State *L) {
563 lu_mem old = g->totalbytes;
564 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
565 if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
566 g->gcstate = GCSsweep; /* end sweep-string phase */
567 lua_assert(old >= g->totalbytes);
568 g->estimate -= old - g->totalbytes;
569}
570
555 571
556static l_mem singlestep (lua_State *L) { 572static l_mem singlestep (lua_State *L) {
557 global_State *g = G(L); 573 global_State *g = G(L);
@@ -570,12 +586,7 @@ static l_mem singlestep (lua_State *L) {
570 } 586 }
571 } 587 }
572 case GCSsweepstring: { 588 case GCSsweepstring: {
573 lu_mem old = g->totalbytes; 589 sweepstrstep(g, L);
574 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
575 if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
576 g->gcstate = GCSsweep; /* end sweep-string phase */
577 lua_assert(old >= g->totalbytes);
578 g->estimate -= old - g->totalbytes;
579 return GCSWEEPCOST; 590 return GCSWEEPCOST;
580 } 591 }
581 case GCSsweep: { 592 case GCSsweep: {
@@ -609,10 +620,14 @@ static l_mem singlestep (lua_State *L) {
609 620
610void luaC_step (lua_State *L) { 621void luaC_step (lua_State *L) {
611 global_State *g = G(L); 622 global_State *g = G(L);
623 if(is_block_gc(L)) return;
624 set_block_gc(L);
612 l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; 625 l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
613 if (lim == 0) 626 if (lim == 0)
614 lim = (MAX_LUMEM-1)/2; /* no limit */ 627 lim = (MAX_LUMEM-1)/2; /* no limit */
615 g->gcdept += g->totalbytes - g->GCthreshold; 628 g->gcdept += g->totalbytes - g->GCthreshold;
629 if (g->estimate > g->totalbytes)
630 g->estimate = g->totalbytes;
616 do { 631 do {
617 lim -= singlestep(L); 632 lim -= singlestep(L);
618 if (g->gcstate == GCSpause) 633 if (g->gcstate == GCSpause)
@@ -629,11 +644,23 @@ void luaC_step (lua_State *L) {
629 else { 644 else {
630 setthreshold(g); 645 setthreshold(g);
631 } 646 }
647 unset_block_gc(L);
632} 648}
633 649
634 650
651int luaC_sweepstrgc (lua_State *L) {
652 global_State *g = G(L);
653 if (g->gcstate == GCSsweepstring) {
654 sweepstrstep(g, L);
655 return (g->gcstate == GCSsweepstring) ? 1 : 0;
656 }
657 return 0;
658}
659
635void luaC_fullgc (lua_State *L) { 660void luaC_fullgc (lua_State *L) {
636 global_State *g = G(L); 661 global_State *g = G(L);
662 if(is_block_gc(L)) return;
663 set_block_gc(L);
637 if (g->gcstate <= GCSpropagate) { 664 if (g->gcstate <= GCSpropagate) {
638 /* reset sweep marks to sweep all elements (returning them to white) */ 665 /* reset sweep marks to sweep all elements (returning them to white) */
639 g->sweepstrgc = 0; 666 g->sweepstrgc = 0;
@@ -649,12 +676,15 @@ void luaC_fullgc (lua_State *L) {
649 while (g->gcstate != GCSfinalize) { 676 while (g->gcstate != GCSfinalize) {
650 lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); 677 lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
651 singlestep(L); 678 singlestep(L);
679 yield();
652 } 680 }
653 markroot(L); 681 markroot(L);
654 while (g->gcstate != GCSpause) { 682 while (g->gcstate != GCSpause) {
655 singlestep(L); 683 singlestep(L);
684 yield();
656 } 685 }
657 setthreshold(g); 686 setthreshold(g);
687 unset_block_gc(L);
658} 688}
659 689
660 690
@@ -682,6 +712,14 @@ void luaC_barrierback (lua_State *L, Table *t) {
682} 712}
683 713
684 714
715void luaC_marknew (lua_State *L, GCObject *o) {
716 global_State *g = G(L);
717 o->gch.marked = luaC_white(g);
718 if (g->gcstate == GCSpropagate)
719 reallymarkobject(g, o); /* mark new objects as gray during propagate state. */
720}
721
722
685void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { 723void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
686 global_State *g = G(L); 724 global_State *g = G(L);
687 o->gch.next = g->rootgc; 725 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 @@
37#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) 37#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2)))
38 38
39 39
40/*
41** Possible Garbage Collector flags.
42** Layout for bit use in 'gsflags' field in global_State structure.
43** bit 0 - Protect GC from recursive calls.
44** bit 1 - Don't try to shrink string table if EGC was called during a string table resize.
45*/
46#define GCFlagsNone 0
47#define GCBlockGCBit 0
48#define GCResizingStringsBit 1
49
50
51#define is_block_gc(L) testbit(G(L)->gcflags, GCBlockGCBit)
52#define set_block_gc(L) l_setbit(G(L)->gcflags, GCBlockGCBit)
53#define unset_block_gc(L) resetbit(G(L)->gcflags, GCBlockGCBit)
54#define is_resizing_strings_gc(L) testbit(G(L)->gcflags, GCResizingStringsBit)
55#define set_resizing_strings_gc(L) l_setbit(G(L)->gcflags, GCResizingStringsBit)
56#define unset_resizing_strings_gc(L) resetbit(G(L)->gcflags, GCResizingStringsBit)
40 57
41/* 58/*
42** Layout for bit use in `marked' field: 59** Layout for bit use in `marked' field:
43** bit 0 - object is white (type 0) 60** bit 0 - object is white (type 0)
44** bit 1 - object is white (type 1) 61** bit 1 - object is white (type 1)
45** bit 2 - object is black 62** bit 2 - object is black
63** bit 3 - for thread: Don't resize thread's stack
46** bit 3 - for userdata: has been finalized 64** bit 3 - for userdata: has been finalized
47** bit 3 - for tables: has weak keys 65** bit 3 - for tables: has weak keys
48** bit 4 - for tables: has weak values 66** bit 4 - for tables: has weak values
@@ -54,6 +72,7 @@
54#define WHITE0BIT 0 72#define WHITE0BIT 0
55#define WHITE1BIT 1 73#define WHITE1BIT 1
56#define BLACKBIT 2 74#define BLACKBIT 2
75#define FIXEDSTACKBIT 3
57#define FINALIZEDBIT 3 76#define FINALIZEDBIT 3
58#define KEYWEAKBIT 3 77#define KEYWEAKBIT 3
59#define VALUEWEAKBIT 4 78#define VALUEWEAKBIT 4
@@ -76,6 +95,9 @@
76 95
77#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) 96#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
78 97
98#define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT)
99#define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT)
100#define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT)
79 101
80#define luaC_checkGC(L) { \ 102#define luaC_checkGC(L) { \
81 condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ 103 condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
@@ -101,6 +123,8 @@ LUAI_FUNC void luaC_callGCTM (lua_State *L);
101LUAI_FUNC void luaC_freeall (lua_State *L); 123LUAI_FUNC void luaC_freeall (lua_State *L);
102LUAI_FUNC void luaC_step (lua_State *L); 124LUAI_FUNC void luaC_step (lua_State *L);
103LUAI_FUNC void luaC_fullgc (lua_State *L); 125LUAI_FUNC void luaC_fullgc (lua_State *L);
126LUAI_FUNC int luaC_sweepstrgc (lua_State *L);
127LUAI_FUNC void luaC_marknew (lua_State *L, GCObject *o);
104LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); 128LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
105LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); 129LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
106LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); 130LUAI_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 {
117#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) 117#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
118 118
119#define setnvalue(obj,x) \ 119#define setnvalue(obj,x) \
120 { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } 120 { lua_Number i_x = (x); TValue *i_o=(obj); i_o->value.n=i_x; i_o->tt=LUA_TNUMBER; }
121 121
122#define setpvalue(obj,x) \ 122#define setpvalue(obj,x) \
123 { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } 123 { void *i_x = (x); TValue *i_o=(obj); i_o->value.p=i_x; i_o->tt=LUA_TLIGHTUSERDATA; }
124 124
125#define setbvalue(obj,x) \ 125#define setbvalue(obj,x) \
126 { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } 126 { int i_x = (x); TValue *i_o=(obj); i_o->value.b=i_x; i_o->tt=LUA_TBOOLEAN; }
127 127
128#define setsvalue(L,obj,x) \ 128#define setsvalue(L,obj,x) \
129 { TValue *i_o=(obj); \ 129 { GCObject *i_x = cast(GCObject *, (x)); \
130 i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ 130 TValue *i_o=(obj); \
131 i_o->value.gc=i_x; i_o->tt=LUA_TSTRING; \
131 checkliveness(G(L),i_o); } 132 checkliveness(G(L),i_o); }
132 133
133#define setuvalue(L,obj,x) \ 134#define setuvalue(L,obj,x) \
134 { TValue *i_o=(obj); \ 135 { GCObject *i_x = cast(GCObject *, (x)); \
135 i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ 136 TValue *i_o=(obj); \
137 i_o->value.gc=i_x; i_o->tt=LUA_TUSERDATA; \
136 checkliveness(G(L),i_o); } 138 checkliveness(G(L),i_o); }
137 139
138#define setthvalue(L,obj,x) \ 140#define setthvalue(L,obj,x) \
139 { TValue *i_o=(obj); \ 141 { GCObject *i_x = cast(GCObject *, (x)); \
140 i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ 142 TValue *i_o=(obj); \
143 i_o->value.gc=i_x; i_o->tt=LUA_TTHREAD; \
141 checkliveness(G(L),i_o); } 144 checkliveness(G(L),i_o); }
142 145
143#define setclvalue(L,obj,x) \ 146#define setclvalue(L,obj,x) \
144 { TValue *i_o=(obj); \ 147 { GCObject *i_x = cast(GCObject *, (x)); \
145 i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ 148 TValue *i_o=(obj); \
149 i_o->value.gc=i_x; i_o->tt=LUA_TFUNCTION; \
146 checkliveness(G(L),i_o); } 150 checkliveness(G(L),i_o); }
147 151
148#define sethvalue(L,obj,x) \ 152#define sethvalue(L,obj,x) \
149 { TValue *i_o=(obj); \ 153 { GCObject *i_x = cast(GCObject *, (x)); \
150 i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ 154 TValue *i_o=(obj); \
155 i_o->value.gc=i_x; i_o->tt=LUA_TTABLE; \
151 checkliveness(G(L),i_o); } 156 checkliveness(G(L),i_o); }
152 157
153#define setptvalue(L,obj,x) \ 158#define setptvalue(L,obj,x) \
154 { TValue *i_o=(obj); \ 159 { GCObject *i_x = cast(GCObject *, (x)); \
155 i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ 160 TValue *i_o=(obj); \
161 i_o->value.gc=i_x; i_o->tt=LUA_TPROTO; \
156 checkliveness(G(L),i_o); } 162 checkliveness(G(L),i_o); }
157 163
158 164
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) {
383Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { 383Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
384 struct LexState lexstate; 384 struct LexState lexstate;
385 struct FuncState funcstate; 385 struct FuncState funcstate;
386 TString *tname = luaS_new(L, name);
387 setsvalue2s(L, L->top, tname); /* protect name */
388 incr_top(L);
386 lexstate.buff = buff; 389 lexstate.buff = buff;
387 luaX_setinput(L, &lexstate, z, luaS_new(L, name)); 390 luaX_setinput(L, &lexstate, z, tname);
388 open_func(&lexstate, &funcstate); 391 open_func(&lexstate, &funcstate);
389 funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ 392 funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
390 luaX_next(&lexstate); /* read first token */ 393 luaX_next(&lexstate); /* read first token */
391 chunk(&lexstate); 394 chunk(&lexstate);
392 check(&lexstate, TK_EOS); 395 check(&lexstate, TK_EOS);
393 close_func(&lexstate); 396 close_func(&lexstate);
397 L->top--; /* remove 'name' from stack */
394 lua_assert(funcstate.prev == NULL); 398 lua_assert(funcstate.prev == NULL);
395 lua_assert(funcstate.f->nups == 0); 399 lua_assert(funcstate.f->nups == 0);
396 lua_assert(lexstate.fs == NULL); 400 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) {
119lua_State *luaE_newthread (lua_State *L) { 119lua_State *luaE_newthread (lua_State *L) {
120 lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); 120 lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
121 luaC_link(L, obj2gco(L1), LUA_TTHREAD); 121 luaC_link(L, obj2gco(L1), LUA_TTHREAD);
122 setthvalue(L, L->top, L1); /* put thread on stack */
123 incr_top(L);
122 preinit_state(L1, G(L)); 124 preinit_state(L1, G(L));
123 stack_init(L1, L); /* init stack */ 125 stack_init(L1, L); /* init stack */
124 setobj2n(L, gt(L1), gt(L)); /* share table of globals */ 126 setobj2n(L, gt(L1), gt(L)); /* share table of globals */
@@ -126,7 +128,8 @@ lua_State *luaE_newthread (lua_State *L) {
126 L1->basehookcount = L->basehookcount; 128 L1->basehookcount = L->basehookcount;
127 L1->hook = L->hook; 129 L1->hook = L->hook;
128 resethookcount(L1); 130 resethookcount(L1);
129 lua_assert(iswhite(obj2gco(L1))); 131 lua_assert(!isdead(G(L), obj2gco(L1)));
132 L->top--; /* remove thread from stack */
130 return L1; 133 return L1;
131} 134}
132 135
@@ -160,6 +163,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
160 g->uvhead.u.l.prev = &g->uvhead; 163 g->uvhead.u.l.prev = &g->uvhead;
161 g->uvhead.u.l.next = &g->uvhead; 164 g->uvhead.u.l.next = &g->uvhead;
162 g->GCthreshold = 0; /* mark it as unfinished state */ 165 g->GCthreshold = 0; /* mark it as unfinished state */
166 g->estimate = 0;
163 g->strt.size = 0; 167 g->strt.size = 0;
164 g->strt.nuse = 0; 168 g->strt.nuse = 0;
165 g->strt.hash = NULL; 169 g->strt.hash = NULL;
@@ -167,6 +171,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
167 luaZ_initbuffer(L, &g->buff); 171 luaZ_initbuffer(L, &g->buff);
168 g->panic = NULL; 172 g->panic = NULL;
169 g->gcstate = GCSpause; 173 g->gcstate = GCSpause;
174 g->gcflags = GCFlagsNone;
170 g->rootgc = obj2gco(L); 175 g->rootgc = obj2gco(L);
171 g->sweepstrgc = 0; 176 g->sweepstrgc = 0;
172 g->sweepgc = &g->rootgc; 177 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 {
71 void *ud; /* auxiliary data to `frealloc' */ 71 void *ud; /* auxiliary data to `frealloc' */
72 lu_byte currentwhite; 72 lu_byte currentwhite;
73 lu_byte gcstate; /* state of garbage collector */ 73 lu_byte gcstate; /* state of garbage collector */
74 lu_byte gcflags; /* flags for the garbage collector */
74 int sweepstrgc; /* position of sweep in `strt' */ 75 int sweepstrgc; /* position of sweep in `strt' */
75 GCObject *rootgc; /* list of all collectable objects */ 76 GCObject *rootgc; /* list of all collectable objects */
76 GCObject **sweepgc; /* position of sweep in `rootgc' */ 77 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 @@
22 22
23 23
24void luaS_resize (lua_State *L, int newsize) { 24void luaS_resize (lua_State *L, int newsize) {
25 GCObject **newhash;
26 stringtable *tb; 25 stringtable *tb;
27 int i; 26 int i;
28 if (G(L)->gcstate == GCSsweepstring)
29 return; /* cannot resize during GC traverse */
30 newhash = luaM_newvector(L, newsize, GCObject *);
31 tb = &G(L)->strt; 27 tb = &G(L)->strt;
32 for (i=0; i<newsize; i++) newhash[i] = NULL; 28 if (luaC_sweepstrgc(L) || newsize == tb->size || is_resizing_strings_gc(L))
29 return; /* cannot resize during GC traverse or doesn't need to be resized */
30 set_resizing_strings_gc(L);
31 if (newsize > tb->size) {
32 luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
33 for (i=tb->size; i<newsize; i++) tb->hash[i] = NULL;
34 }
33 /* rehash */ 35 /* rehash */
34 for (i=0; i<tb->size; i++) { 36 for (i=0; i<tb->size; i++) {
35 GCObject *p = tb->hash[i]; 37 GCObject *p = tb->hash[i];
38 tb->hash[i] = NULL;
36 while (p) { /* for each node in the list */ 39 while (p) { /* for each node in the list */
37 GCObject *next = p->gch.next; /* save next */ 40 GCObject *next = p->gch.next; /* save next */
38 unsigned int h = gco2ts(p)->hash; 41 unsigned int h = gco2ts(p)->hash;
39 int h1 = lmod(h, newsize); /* new position */ 42 int h1 = lmod(h, newsize); /* new position */
40 lua_assert(cast_int(h%newsize) == lmod(h, newsize)); 43 lua_assert(cast_int(h%newsize) == lmod(h, newsize));
41 p->gch.next = newhash[h1]; /* chain it */ 44 p->gch.next = tb->hash[h1]; /* chain it */
42 newhash[h1] = p; 45 tb->hash[h1] = p;
43 p = next; 46 p = next;
44 } 47 }
45 } 48 }
46 luaM_freearray(L, tb->hash, tb->size, TString *); 49 if (newsize < tb->size)
50 luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
47 tb->size = newsize; 51 tb->size = newsize;
48 tb->hash = newhash; 52 unset_resizing_strings_gc(L);
49} 53}
50 54
51 55
@@ -55,6 +59,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
55 stringtable *tb; 59 stringtable *tb;
56 if (l > ((MAX_SIZET - sizeof(TString))/sizeof(char)) - sizeof("")) 60 if (l > ((MAX_SIZET - sizeof(TString))/sizeof(char)) - sizeof(""))
57 luaM_toobig(L); 61 luaM_toobig(L);
62 tb = &G(L)->strt;
63 if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
64 luaS_resize(L, tb->size*2); /* too crowded */
58 ts = cast(TString *, luaM_malloc(L, sizetstring(type, l))); 65 ts = cast(TString *, luaM_malloc(L, sizetstring(type, l)));
59 ts->tsv.len = l; 66 ts->tsv.len = l;
60 ts->tsv.hash = h; 67 ts->tsv.hash = h;
@@ -70,13 +77,10 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
70 memcpy(ts+1, str, l*sizeof(char)); 77 memcpy(ts+1, str, l*sizeof(char));
71 ((char *)(ts+1))[l] = '\0'; /* ending 0 */ 78 ((char *)(ts+1))[l] = '\0'; /* ending 0 */
72 } 79 }
73 tb = &G(L)->strt;
74 h = lmod(h, tb->size); 80 h = lmod(h, tb->size);
75 ts->tsv.next = tb->hash[h]; /* chain new entry */ 81 ts->tsv.next = tb->hash[h]; /* chain new entry */
76 tb->hash[h] = obj2gco(ts); 82 tb->hash[h] = obj2gco(ts);
77 tb->nuse++; 83 tb->nuse++;
78 if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
79 luaS_resize(L, tb->size*2); /* too crowded */
80 return ts; 84 return ts;
81} 85}
82 86
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) {
358Table *luaH_new (lua_State *L, int narray, int nhash) { 358Table *luaH_new (lua_State *L, int narray, int nhash) {
359 Table *t = luaM_new(L, Table); 359 Table *t = luaM_new(L, Table);
360 luaC_link(L, obj2gco(t), LUA_TTABLE); 360 luaC_link(L, obj2gco(t), LUA_TTABLE);
361 sethvalue2s(L, L->top, t); /* put table on stack */
362 incr_top(L);
361 t->metatable = NULL; 363 t->metatable = NULL;
362 t->flags = cast_byte(~0); 364 t->flags = cast_byte(~0);
363 /* temporary values (kept only if some malloc fails) */ 365 /* temporary values (kept only if some malloc fails) */
@@ -367,6 +369,7 @@ Table *luaH_new (lua_State *L, int narray, int nhash) {
367 t->node = cast(Node *, dummynode); 369 t->node = cast(Node *, dummynode);
368 setarrayvector(L, t, narray); 370 setarrayvector(L, t, narray);
369 setnodevector(L, t, nhash); 371 setnodevector(L, t, nhash);
372 L->top--; /* remove table from stack */
370 return t; 373 return t;
371} 374}
372 375
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 @@
1#include "plugin.h"
2#include "lstate.h"
3#include LUA_USER_H
4
5/* lua Out Of Memory */
6static struct lua_OOM l_oom = {NULL, 0};
7
8int set_lua_OOM(lua_State * L)
9{
10 l_oom.L = L;
11 l_oom.count++;
12 return 0;
13}
14
15struct lua_OOM *get_lua_OOM(void)
16{
17 return &l_oom;
18}
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 @@
1#ifndef _LUA_USER_H_
2#define _LUA_USER_H_
3
4#define LUA_OOM(L) set_lua_OOM(L)
5
6struct lua_OOM {
7 lua_State * L;
8 int count;
9};
10
11int set_lua_OOM(lua_State * L);
12
13struct lua_OOM* get_lua_OOM(void);
14#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);
810/*Rocklua functions*/ 810/*Rocklua functions*/
811#include "rockconf.h" 811#include "rockconf.h"
812 812
813/* heap */
814#undef LUAI_GCPAUSE /*200*/
815#define LUAI_GCPAUSE 125
816#define MINSTRTABSIZE 512 /*32*/
817
813/*else*/ 818/*else*/
819#define LUA_USER_H "lua_user.h"
814#define LUA_DISABLE_BYTECODE 820#define LUA_DISABLE_BYTECODE
815 821
816#endif 822#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) {
49 return 0; 49 return 0;
50 else { 50 else {
51 char s[LUAI_MAXNUMBER2STR]; 51 char s[LUAI_MAXNUMBER2STR];
52 ptrdiff_t objr = savestack(L, obj);
52 lua_Number n = nvalue(obj); 53 lua_Number n = nvalue(obj);
53 lua_number2str(s, n); 54 lua_number2str(s, n);
54 setsvalue2s(L, obj, luaS_new(L, s)); 55 setsvalue2s(L, restorestack(L, objr), luaS_new(L, s));
55 return 1; 56 return 1;
56 } 57 }
57} 58}
@@ -134,6 +135,9 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
134void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { 135void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
135 int loop; 136 int loop;
136 TValue temp; 137 TValue temp;
138 setnilvalue(L->top);
139 L->top++;
140 fixedstack(L);
137 for (loop = 0; loop < MAXTAGLOOP; loop++) { 141 for (loop = 0; loop < MAXTAGLOOP; loop++) {
138 const TValue *tm; 142 const TValue *tm;
139 if (ttistable(t)) { /* `t' is a table? */ 143 if (ttistable(t)) { /* `t' is a table? */
@@ -141,6 +145,8 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
141 TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ 145 TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
142 if (!ttisnil(oldval) || /* result is no nil? */ 146 if (!ttisnil(oldval) || /* result is no nil? */
143 (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ 147 (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
148 L->top--;
149 unfixedstack(L);
144 setobj2t(L, oldval, val); 150 setobj2t(L, oldval, val);
145 h->flags = 0; 151 h->flags = 0;
146 luaC_barriert(L, h, val); 152 luaC_barriert(L, h, val);
@@ -151,12 +157,15 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
151 else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) 157 else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
152 luaG_typeerror(L, t, "index"); 158 luaG_typeerror(L, t, "index");
153 if (ttisfunction(tm)) { 159 if (ttisfunction(tm)) {
160 L->top--;
161 unfixedstack(L);
154 callTM(L, tm, t, key, val); 162 callTM(L, tm, t, key, val);
155 return; 163 return;
156 } 164 }
157 /* else repeat with `tm' */ 165 /* else repeat with `tm' */
158 setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ 166 setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */
159 t = &temp; 167 t = &temp;
168 setobj2s(L, L->top-1, t); /* need to protect value from EGC. */
160 } 169 }
161 luaG_runerror(L, "loop in settable"); 170 luaG_runerror(L, "loop in settable");
162} 171}
@@ -284,8 +293,11 @@ void luaV_concat (lua_State *L, int total, int last) {
284 StkId top = L->base + last + 1; 293 StkId top = L->base + last + 1;
285 int n = 2; /* number of elements handled in this pass (at least 2) */ 294 int n = 2; /* number of elements handled in this pass (at least 2) */
286 if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { 295 if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
287 if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) 296 if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) {
297 /* restore 'top' pointer, since stack might have been reallocted */
298 top = L->base + last + 1;
288 luaG_concaterror(L, top-2, top-1); 299 luaG_concaterror(L, top-2, top-1);
300 }
289 } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ 301 } else if (tsvalue(top-1)->len == 0) /* second op is empty? */
290 (void)tostring(L, top - 2); /* result is first op (as string) */ 302 (void)tostring(L, top - 2); /* result is first op (as string) */
291 else { 303 else {
@@ -293,12 +305,14 @@ void luaV_concat (lua_State *L, int total, int last) {
293 size_t tl = tsvalue(top-1)->len; 305 size_t tl = tsvalue(top-1)->len;
294 char *buffer; 306 char *buffer;
295 int i; 307 int i;
308 fixedstack(L);
296 /* collect total length */ 309 /* collect total length */
297 for (n = 1; n < total && tostring(L, top-n-1); n++) { 310 for (n = 1; n < total && tostring(L, top-n-1); n++) {
298 size_t l = tsvalue(top-n-1)->len; 311 size_t l = tsvalue(top-n-1)->len;
299 if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); 312 if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
300 tl += l; 313 tl += l;
301 } 314 }
315 G(L)->buff.n = tl;
302 buffer = luaZ_openspace(L, &G(L)->buff, tl); 316 buffer = luaZ_openspace(L, &G(L)->buff, tl);
303 tl = 0; 317 tl = 0;
304 for (i=n; i>0; i--) { /* concat all strings */ 318 for (i=n; i>0; i--) { /* concat all strings */
@@ -307,6 +321,8 @@ void luaV_concat (lua_State *L, int total, int last) {
307 tl += l; 321 tl += l;
308 } 322 }
309 setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); 323 setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
324 luaZ_resetbuffer(&G(L)->buff);
325 unfixedstack(L);
310 } 326 }
311 total -= n-1; /* got `n' strings to create 1 new */ 327 total -= n-1; /* got `n' strings to create 1 new */
312 last -= n-1; 328 last -= n-1;
@@ -332,8 +348,13 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
332 default: lua_assert(0); break; 348 default: lua_assert(0); break;
333 } 349 }
334 } 350 }
335 else if (!call_binTM(L, rb, rc, ra, op)) 351 else {
336 luaG_aritherror(L, rb, rc); 352 ptrdiff_t br = savestack(L, rb);
353 ptrdiff_t cr = savestack(L, rc);
354 if (!call_binTM(L, rb, rc, ra, op)) {
355 luaG_aritherror(L, restorestack(L, br), restorestack(L, cr));
356 }
357 }
337} 358}
338 359
339 360
@@ -461,7 +482,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
461 case OP_NEWTABLE: { 482 case OP_NEWTABLE: {
462 int b = GETARG_B(i); 483 int b = GETARG_B(i);
463 int c = GETARG_C(i); 484 int c = GETARG_C(i);
464 sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); 485 Table *h;
486 Protect(h = luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
487 sethvalue(L, RA(i), h);
465 Protect(luaC_checkGC(L)); 488 Protect(luaC_checkGC(L));
466 continue; 489 continue;
467 } 490 }
@@ -547,9 +570,10 @@ void luaV_execute (lua_State *L, int nexeccalls) {
547 break; 570 break;
548 } 571 }
549 default: { /* try metamethod */ 572 default: { /* try metamethod */
573 ptrdiff_t br = savestack(L, rb);
550 Protect( 574 Protect(
551 if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) 575 if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
552 luaG_typeerror(L, rb, "get length of"); 576 luaG_typeerror(L, restorestack(L, br), "get length of");
553 ) 577 )
554 } 578 }
555 } 579 }
@@ -723,6 +747,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
723 int c = GETARG_C(i); 747 int c = GETARG_C(i);
724 int last; 748 int last;
725 Table *h; 749 Table *h;
750 fixedstack(L);
726 if (n == 0) { 751 if (n == 0) {
727 n = cast_int(L->top - ra) - 1; 752 n = cast_int(L->top - ra) - 1;
728 L->top = L->ci->top; 753 L->top = L->ci->top;
@@ -738,6 +763,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
738 setobj2t(L, luaH_setnum(L, h, last--), val); 763 setobj2t(L, luaH_setnum(L, h, last--), val);
739 luaC_barriert(L, h, val); 764 luaC_barriert(L, h, val);
740 } 765 }
766 unfixedstack(L);
741 continue; 767 continue;
742 } 768 }
743 case OP_CLOSE: { 769 case OP_CLOSE: {
@@ -750,7 +776,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
750 int nup, j; 776 int nup, j;
751 p = cl->p->p[GETARG_Bx(i)]; 777 p = cl->p->p[GETARG_Bx(i)];
752 nup = p->nups; 778 nup = p->nups;
779 fixedstack(L);
753 ncl = luaF_newLclosure(L, nup, cl->env); 780 ncl = luaF_newLclosure(L, nup, cl->env);
781 setclvalue(L, ra, ncl);
754 ncl->l.p = p; 782 ncl->l.p = p;
755 for (j=0; j<nup; j++, pc++) { 783 for (j=0; j<nup; j++, pc++) {
756 if (GET_OPCODE(*pc) == OP_GETUPVAL) 784 if (GET_OPCODE(*pc) == OP_GETUPVAL)
@@ -760,7 +788,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
760 ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); 788 ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
761 } 789 }
762 } 790 }
763 setclvalue(L, ra, ncl); 791 unfixedstack(L);
764 Protect(luaC_checkGC(L)); 792 Protect(luaC_checkGC(L));
765 continue; 793 continue;
766 } 794 }
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 {
27 size_t buffsize; 27 size_t buffsize;
28} Mbuffer; 28} Mbuffer;
29 29
30#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) 30#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->n = 0, (buff)->buffsize = 0)
31 31
32#define luaZ_buffer(buff) ((buff)->buffer) 32#define luaZ_buffer(buff) ((buff)->buffer)
33#define luaZ_sizebuffer(buff) ((buff)->buffsize) 33#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);
63#define strcmp rb->strcmp 63#define strcmp rb->strcmp
64#define strcpy rb->strcpy 64#define strcpy rb->strcpy
65#define strlen rb->strlen 65#define strlen rb->strlen
66#define yield() rb->yield()
66 67
67#endif /* _ROCKCONF_H_ */ 68#endif /* _ROCKCONF_H_ */
68 69
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)
304 break; 304 break;
305 } 305 }
306 306
307 rb->yield(); 307 yield();
308 lua_pushinteger(L, result); 308 lua_pushinteger(L, result);
309 return 1; 309 return 1;
310} 310}
@@ -382,7 +382,7 @@ RB_WRAP(audio)
382 return 1; 382 return 1;
383 } 383 }
384 384
385 rb->yield(); 385 yield();
386 lua_pushinteger(L, status); /* return previous (or current) audio status */ 386 lua_pushinteger(L, status); /* return previous (or current) audio status */
387 return 1; 387 return 1;
388} 388}
@@ -502,7 +502,7 @@ RB_WRAP(pcm)
502 break; 502 break;
503 } 503 }
504 504
505 rb->yield(); 505 yield();
506 return 1; 506 return 1;
507} 507}
508 508
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 @@
20 20
21#include "plugin.h" 21#include "plugin.h"
22#include <tlsf.h> 22#include <tlsf.h>
23#include "lua.h"
23 24
24void *get_new_area(size_t *size) 25void *get_new_area(size_t *size)
25{ 26{
@@ -36,7 +37,8 @@ void *get_new_area(size_t *size)
36 return pluginbuf_ptr; 37 return pluginbuf_ptr;
37 } 38 }
38 39
39 if (audiobuf_ptr == NULL) 40 /* only grab the next area if lua already tried + failed to garbage collect*/
41 if (audiobuf_ptr == NULL && (get_lua_OOM())->count > 0)
40 { 42 {
41 /* grab audiobuffer */ 43 /* grab audiobuffer */
42 audiobuf_ptr = rb->plugin_get_audio_buffer(size); 44 audiobuf_ptr = rb->plugin_get_audio_buffer(size);