diff options
author | Lua Team <team@lua.org> | 2010-05-18 12:00:00 +0000 |
---|---|---|
committer | repogen <> | 2010-05-18 12:00:00 +0000 |
commit | f970e1e83ed07bbcf8a20fc1a95f91a0a2aae620 (patch) | |
tree | 005b26e8ebf7553ba5c7a66700866be3e42443d0 /src | |
parent | ecd48c2901f08a88db32139b97c35c59eba1f19e (diff) | |
download | lua-github-f970e1e83ed07bbcf8a20fc1a95f91a0a2aae620.tar.gz |
Lua 5.2.0-work35.2.0-work3
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 10 | ||||
-rw-r--r-- | src/lapi.c | 240 | ||||
-rw-r--r-- | src/lauxlib.c | 201 | ||||
-rw-r--r-- | src/lauxlib.h | 39 | ||||
-rw-r--r-- | src/lbaselib.c | 95 | ||||
-rw-r--r-- | src/lbitlib.c | 34 | ||||
-rw-r--r-- | src/lcode.c | 51 | ||||
-rw-r--r-- | src/lcode.h | 8 | ||||
-rw-r--r-- | src/ldblib.c | 30 | ||||
-rw-r--r-- | src/ldebug.c | 116 | ||||
-rw-r--r-- | src/ldo.c | 75 | ||||
-rw-r--r-- | src/ldump.c | 3 | ||||
-rw-r--r-- | src/lfunc.c | 23 | ||||
-rw-r--r-- | src/lfunc.h | 6 | ||||
-rw-r--r-- | src/lgc.c | 692 | ||||
-rw-r--r-- | src/lgc.h | 91 | ||||
-rw-r--r-- | src/linit.c | 9 | ||||
-rw-r--r-- | src/liolib.c | 129 | ||||
-rw-r--r-- | src/llex.c | 116 | ||||
-rw-r--r-- | src/llex.h | 3 | ||||
-rw-r--r-- | src/llimits.h | 13 | ||||
-rw-r--r-- | src/lmem.c | 29 | ||||
-rw-r--r-- | src/lmem.h | 4 | ||||
-rw-r--r-- | src/loadlib.c | 31 | ||||
-rw-r--r-- | src/lobject.c | 38 | ||||
-rw-r--r-- | src/lobject.h | 58 | ||||
-rw-r--r-- | src/lopcodes.c | 10 | ||||
-rw-r--r-- | src/lopcodes.h | 9 | ||||
-rw-r--r-- | src/lparser.c | 184 | ||||
-rw-r--r-- | src/lparser.h | 11 | ||||
-rw-r--r-- | src/lstate.c | 80 | ||||
-rw-r--r-- | src/lstate.h | 34 | ||||
-rw-r--r-- | src/lstring.c | 8 | ||||
-rw-r--r-- | src/lstring.h | 12 | ||||
-rw-r--r-- | src/lstrlib.c | 132 | ||||
-rw-r--r-- | src/ltable.c | 7 | ||||
-rw-r--r-- | src/ltablib.c | 20 | ||||
-rw-r--r-- | src/ltm.c | 4 | ||||
-rw-r--r-- | src/ltm.h | 5 | ||||
-rw-r--r-- | src/lua.c | 52 | ||||
-rw-r--r-- | src/lua.h | 30 | ||||
-rw-r--r-- | src/luac.c | 31 | ||||
-rw-r--r-- | src/luaconf.h | 71 | ||||
-rw-r--r-- | src/lundump.c | 3 | ||||
-rw-r--r-- | src/lvm.c | 334 | ||||
-rw-r--r-- | src/print.c | 21 |
46 files changed, 1747 insertions, 1455 deletions
diff --git a/src/Makefile b/src/Makefile index a3942a5b..83185e34 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,7 +27,7 @@ CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ ltm.o lundump.o lvm.o lzio.o LIB_O= lauxlib.o lbaselib.o lbitlib.o ldblib.o liolib.o lmathlib.o loslib.o \ - ltablib.o lstrlib.o loadlib.o linit.o + lstrlib.o ltablib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o @@ -103,7 +103,7 @@ macosx: $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_MACOSX" MYLIBS="-lreadline" mingw: - $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ + $(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe @@ -137,8 +137,8 @@ ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ lstring.h ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h -lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ - lopcodes.h lstate.h ltm.h lzio.h +lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \ + lstate.h ltm.h lzio.h lmem.h lopcodes.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h @@ -163,7 +163,7 @@ lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h + ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.111 2010/01/13 16:18:25 roberto Exp $ +** $Id: lapi.c,v 2.129 2010/05/14 13:15:26 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -39,16 +39,6 @@ const char lua_ident[] = "invalid index") -static Table *getcurrenv (lua_State *L) { - if (L->ci->previous == NULL) /* no enclosing function? */ - return G(L)->l_gt; /* use global table as environment */ - else { - Closure *func = curr_func(L); - return func->c.env; - } -} - - static TValue *index2addr (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { @@ -61,26 +51,25 @@ static TValue *index2addr (lua_State *L, int idx) { api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } - else switch (idx) { /* pseudo-indices */ - case LUA_REGISTRYINDEX: return &G(L)->l_registry; - case LUA_ENVIRONINDEX: { - sethvalue(L, &L->env, getcurrenv(L)); - return &L->env; - } - default: { - Closure *func = curr_func(L); - idx = LUA_ENVIRONINDEX - idx; - api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return cast(TValue *, luaO_nilobject); /* it has no upvalues */ + else { + Closure *func = clvalue(ci->func); return (idx <= func->c.nupvalues) - ? &func->c.upvalue[idx-1] - : cast(TValue *, luaO_nilobject); + ? &func->c.upvalue[idx-1] + : cast(TValue *, luaO_nilobject); } } } /* -** to be caled by 'lua_checkstack' in protected mode, to grow stack +** to be called by 'lua_checkstack' in protected mode, to grow stack ** capturing memory errors */ static void growstack (lua_State *L, void *ud) { @@ -147,6 +136,16 @@ LUA_API const lua_Number *lua_version (lua_State *L) { */ +/* +** convert an acceptable stack index into an absolute index +*/ +LUA_API int lua_absindex (lua_State *L, int idx) { + return (idx > 0 || idx <= LUA_REGISTRYINDEX) + ? idx + : cast_int(L->top - L->ci->func + idx); +} + + LUA_API int lua_gettop (lua_State *L) { return cast_int(L->top - (L->ci->func + 1)); } @@ -195,16 +194,10 @@ LUA_API void lua_insert (lua_State *L, int idx) { static void moveto (lua_State *L, TValue *fr, int idx) { TValue *to = index2addr(L, idx); api_checkvalidindex(L, to); - if (idx == LUA_ENVIRONINDEX) { - Closure *func = curr_func(L); - api_check(L, ttistable(fr), "table expected"); - func->c.env = hvalue(fr); - luaC_barrier(L, func, fr); - } - else { - setobj(L, to, fr); - if (idx < LUA_ENVIRONINDEX) /* function upvalue? */ - luaC_barrier(L, curr_func(L), fr); + setobj(L, to, fr); + if (idx < LUA_REGISTRYINDEX) { /* function upvalue? */ + lua_assert(ttisclosure(L->ci->func)); + luaC_barrier(L, clvalue(L->ci->func), fr); } /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ @@ -213,9 +206,6 @@ static void moveto (lua_State *L, TValue *fr, int idx) { LUA_API void lua_replace (lua_State *L, int idx) { lua_lock(L); - /* explicit test for incompatible code */ - if (idx == LUA_ENVIRONINDEX && L->ci->previous == NULL) - luaG_runerror(L, "no calling environment"); api_checknelems(L, 1); moveto(L, L->top - 1, idx); L->top--; @@ -249,19 +239,19 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); + return (o == luaO_nilobject) ? LUA_TNONE : ttypenv(o); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); - return typename(t); + return ttypename(t); } LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return iscfunction(o); + return (ttislcf(o) || (ttisclosure(o) && clvalue(o)->c.isC)); } @@ -387,7 +377,10 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; + if (ttislcf(o)) return fvalue(o); + else if (ttisclosure(o) && clvalue(o)->c.isC) + return clvalue(o)->c.f; + else return NULL; /* not a C function */ } @@ -412,6 +405,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); + case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: @@ -468,8 +462,16 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) { lua_pushnil(L); return NULL; } - else - return lua_pushlstring(L, s, strlen(s)); + else { + TString *ts; + lua_lock(L); + luaC_checkGC(L); + ts = luaS_new(L, s); + setsvalue2s(L, L->top, ts); + api_incr_top(L); + lua_unlock(L); + return getstr(ts); + } } @@ -498,18 +500,22 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - Closure *cl; lua_lock(L); - api_checknelems(L, n); - api_check(L, n <= UCHAR_MAX, "upvalue index too large"); - luaC_checkGC(L); - cl = luaF_newCclosure(L, n, getcurrenv(L)); - cl->c.f = fn; - L->top -= n; - while (n--) - setobj2n(L, &cl->c.upvalue[n], L->top+n); - setclvalue(L, L->top, cl); - lua_assert(iswhite(obj2gco(cl))); + if (n == 0) { + setfvalue(L->top, fn); + } + else { + Closure *cl; + api_checknelems(L, n); + api_check(L, n <= UCHAR_MAX, "upvalue index too large"); + luaC_checkGC(L); + cl = luaF_newCclosure(L, n); + cl->c.f = fn; + L->top -= n; + while (n--) + setobj2n(L, &cl->c.upvalue[n], L->top + n); + setclvalue(L, L->top, cl); + } api_incr_top(L); lua_unlock(L); } @@ -616,7 +622,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { mt = uvalue(obj)->metatable; break; default: - mt = G(L)->mt[ttype(obj)]; + mt = G(L)->mt[ttypenv(obj)]; break; } if (mt == NULL) @@ -631,22 +637,16 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { } -LUA_API void lua_getfenv (lua_State *L, int idx) { +LUA_API void lua_getenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); api_checkvalidindex(L, o); - switch (ttype(o)) { - case LUA_TFUNCTION: - sethvalue(L, L->top, clvalue(o)->c.env); - break; - case LUA_TUSERDATA: - sethvalue(L, L->top, uvalue(o)->env); - break; - default: - setnilvalue(L->top); - break; - } + api_check(L, ttisuserdata(o), "userdata expected"); + if (uvalue(o)->env) { + sethvalue(L, L->top, uvalue(o)->env); + } else + setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } @@ -737,7 +737,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { break; } default: { - G(L)->mt[ttype(obj)] = mt; + G(L)->mt[ttypenv(obj)] = mt; break; } } @@ -747,29 +747,22 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { } -LUA_API int lua_setfenv (lua_State *L, int idx) { +LUA_API void lua_setenv (lua_State *L, int idx) { StkId o; - int res = 1; lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); api_checkvalidindex(L, o); - api_check(L, ttistable(L->top - 1), "table expected"); - switch (ttype(o)) { - case LUA_TFUNCTION: - clvalue(o)->c.env = hvalue(L->top - 1); - break; - case LUA_TUSERDATA: - uvalue(o)->env = hvalue(L->top - 1); - break; - default: - res = 0; - break; + api_check(L, ttisuserdata(o), "userdata expected"); + if (ttisnil(L->top - 1)) + uvalue(o)->env = NULL; + else { + api_check(L, ttistable(L->top - 1), "table expected"); + uvalue(o)->env = hvalue(L->top - 1); + luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); } - if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); L->top--; lua_unlock(L); - return res; } @@ -857,7 +850,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, ci->u.c.k = k; /* save continuation */ ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ - ci->u.c.oldtop = savestack(L, c.func); + ci->u.c.extra = savestack(L, c.func); ci->u.c.old_allowhook = L->allowhook; ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; @@ -882,6 +875,18 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname); + if (status == LUA_OK) { /* no errors? */ + Closure *f = clvalue(L->top - 1); /* get newly created function */ + lua_assert(!f->c.isC); + if (f->l.nupvalues == 1) { /* does it have one upvalue? */ + /* get global table from registry */ + Table *reg = hvalue(&G(L)->l_registry); + const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + /* set global table as 1st upvalue of 'f' (may be _ENV) */ + setobj(L, f->l.upvals[0]->v, gt); + luaC_barrier(L, f->l.upvals[0], gt); + } + } lua_unlock(L); return status; } @@ -918,11 +923,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; + stopgc(g); break; } case LUA_GCRESTART: { - g->GCthreshold = g->totalbytes; + g->GCdebt = 0; break; } case LUA_GCCOLLECT: { @@ -939,18 +944,22 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCSTEP: { - lu_mem oldts = g->GCthreshold; - lu_mem a = (cast(lu_mem, data) << 10); - g->GCthreshold = (a <= g->totalbytes) ? g->totalbytes - a : 0; - while (g->GCthreshold <= g->totalbytes) { - luaC_step(L); - if (g->gcstate == GCSpause) { /* end of cycle? */ - res = 1; /* signal it */ - break; + int stopped = gcstopped(g); + if (g->gckind == KGC_GEN) { /* generational mode? */ + res = (g->lastmajormem == 0); /* 1 if will do major collection */ + luaC_step(L); /* do a single step */ + } + else { + while (data-- >= 0) { + luaC_step(L); + if (g->gcstate == GCSpause) { /* end of cycle? */ + res = 1; /* signal it */ + break; + } } } - if (oldts == MAX_LUMEM) /* collector was stopped? */ - g->GCthreshold = oldts; /* keep it that way */ + if (stopped) /* collector was stopped? */ + stopgc(g); /* keep it that way */ break; } case LUA_GCSETPAUSE: { @@ -964,7 +973,15 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCISRUNNING: { - res = (g->GCthreshold != MAX_LUMEM); + res = !gcstopped(g); + break; + } + case LUA_GCGEN: { /* change collector to generational mode */ + luaC_changemode(L, KGC_GEN); + break; + } + case LUA_GCINC: { /* change collector to incremental mode */ + luaC_changemode(L, KGC_NORMAL); break; } default: res = -1; /* invalid option */ @@ -1054,7 +1071,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); - u = luaS_newudata(L, size, getcurrenv(L)); + u = luaS_newudata(L, size, NULL); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); @@ -1064,19 +1081,22 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { -static const char *aux_upvalue (StkId fi, int n, TValue **val) { +static const char *aux_upvalue (StkId fi, int n, TValue **val, + GCObject **owner) { Closure *f; - if (!ttisfunction(fi)) return NULL; + if (!ttisclosure(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { if (!(1 <= n && n <= f->c.nupvalues)) return NULL; *val = &f->c.upvalue[n-1]; + if (owner) *owner = obj2gco(f); return ""; } else { Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; + if (owner) *owner = obj2gco(f->l.upvals[n - 1]); return getstr(p->upvalues[n-1].name); } } @@ -1086,7 +1106,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1099,15 +1119,16 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; + GCObject *owner; StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val); + name = aux_upvalue(fi, n, &val, &owner); if (name) { L->top--; setobj(L, val, L->top); - luaC_barrier(L, clvalue(fi), L->top); + luaC_barrier(L, owner, L->top); } lua_unlock(L); return name; @@ -1118,7 +1139,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { Closure *f; Proto *p; StkId fi = index2addr(L, fidx); - api_check(L, ttisfunction(fi), "function expected"); + api_check(L, ttisclosure(fi), "Lua function expected"); f = clvalue(fi); api_check(L, !f->c.isC, "Lua function expected"); p = f->l.p; @@ -1131,7 +1152,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { Closure *f; StkId fi = index2addr(L, fidx); - api_check(L, ttisfunction(fi), "function expected"); + api_check(L, ttisclosure(fi), "function expected"); f = clvalue(fi); if (f->c.isC) { api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index"); @@ -1150,12 +1171,3 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, luaC_objbarrier(L, f1, *up2); } - -#if defined(LUA_COMPAT_CPCALL) -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); - lua_pushlightuserdata(L, &func); - lua_pushlightuserdata(L, ud); - return lua_pcall(L, 2, 0, 0); -} -#endif diff --git a/src/lauxlib.c b/src/lauxlib.c index 9972555e..8ebc18fa 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.196 2009/12/22 15:32:50 roberto Exp $ +** $Id: lauxlib.c,v 1.212 2010/05/18 17:21:24 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -24,11 +24,6 @@ #include "lauxlib.h" -/* convert a stack index to positive */ -#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ - lua_gettop(L) + (i) + 1) - - /* ** {====================================================== ** Traceback @@ -347,54 +342,40 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, ** ======================================================= */ - -#define bufflen(B) ((B)->p - (B)->buffer) -#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) - -#define LIMIT (LUA_MINSTACK/2) - - -static int emptybuffer (luaL_Buffer *B) { - size_t l = bufflen(B); - if (l == 0) return 0; /* put nothing on stack */ - else { - lua_pushlstring(B->L, B->buffer, l); - B->p = B->buffer; - B->lvl++; - return 1; - } -} +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->initb) -static void adjuststack (luaL_Buffer *B) { - if (B->lvl > 1) { - lua_State *L = B->L; - int toget = 1; /* number of levels to concat */ - size_t toplen = lua_rawlen(L, -1); - do { - size_t l = lua_rawlen(L, -(toget+1)); - if (B->lvl - toget + 1 >= LIMIT || toplen > l) { - toplen += l; - toget++; - } - else break; - } while (toget < B->lvl); - lua_concat(L, toget); - B->lvl = B->lvl - toget + 1; +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + lua_State *L = B->L; + if (B->size - B->n < sz) { /* not enough space? */ + char *newbuff; + size_t newsize = B->size * 2; /* double buffer size */ + if (newsize - B->n < sz) /* not bit enough? */ + newsize = B->n + sz; + if (newsize < B->n || newsize - B->n < sz) + luaL_error(L, "string too large"); + newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */ + memcpy(newbuff, B->b, B->n); /* move content to new buffer */ + if (buffonstack(B)) + lua_remove(L, -2); /* remove old buffer */ + B->b = newbuff; + B->size = newsize; } -} - - -LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { - if (emptybuffer(B)) - adjuststack(B); - return B->buffer; + return &B->b[B->n]; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - while (l--) - luaL_addchar(B, *s++); + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l); + luaL_addsize(B, l); } @@ -404,35 +385,41 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { - emptybuffer(B); - lua_concat(B->L, B->lvl); - B->lvl = 1; + lua_State *L = B->L; + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) + lua_remove(L, -2); /* remove old buffer */ +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; - size_t vl; - const char *s = lua_tolstring(L, -1, &vl); - if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, s, vl); /* put it there */ - B->p += vl; - lua_pop(L, 1); /* remove from stack */ - } - else { - if (emptybuffer(B)) - lua_insert(L, -2); /* put buffer before new value */ - B->lvl++; /* add new value into B stack */ - adjuststack(B); - } + size_t l; + const char *s = lua_tolstring(L, -1, &l); + if (buffonstack(B)) + lua_insert(L, -2); /* put value below buffer */ + luaL_addlstring(B, s, l); + lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer"); B->L = L; - B->p = B->buffer; - B->lvl = 0; + B->b = B->initb; + B->n = 0; + B->size = LUAL_BUFFERSIZE; +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return luaL_prepbuffsize(B, sz); } /* }====================================================== */ @@ -444,32 +431,26 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { ** ======================================================= */ -/* number of prereserved references (for internal use) */ -#define FREELIST_REF (LUA_RIDX_LAST + 1) /* free list of references */ +/* index of free-list header */ +#define freelist "lua-freelist" LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; - t = abs_index(L, t); + t = lua_absindex(L, t); if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } - lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ + lua_getfield(L, t, freelist); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ + lua_setfield(L, t, freelist); /* (t[freelist] = t[ref]) */ } - else { /* no free elements */ + else /* no free elements */ ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ - if (ref == FREELIST_REF) { /* FREELIST_REF not initialized? */ - lua_pushinteger(L, 0); - lua_rawseti(L, t, FREELIST_REF); - ref = FREELIST_REF + 1; - } - } lua_rawseti(L, t, ref); return ref; } @@ -477,11 +458,11 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { - t = abs_index(L, t); - lua_rawgeti(L, t, FREELIST_REF); - lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ + t = lua_absindex(L, t); + lua_getfield(L, t, freelist); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_pushinteger(L, ref); - lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ + lua_setfield(L, t, freelist); /* t[freelist] = ref */ } } @@ -495,7 +476,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { - int extraline; + int first; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; @@ -504,17 +485,19 @@ typedef struct LoadF { static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; - if (lf->extraline) { - lf->extraline = 0; + if (lf->first != EOF) { *size = 1; - return "\n"; + lf->buff[0] = (char)lf->first; + lf->first = EOF; + } + else { + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); } - /* 'fread' can return > 0 *and* set the EOF flag. If next call to - 'getF' calls 'fread', terminal may still wait for user input. - The next check avoids this problem. */ - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); - return (*size > 0) ? lf->buff : NULL; + return lf->buff; } @@ -532,7 +515,6 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - lf.extraline = 0; if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; @@ -544,18 +526,14 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { } c = getc(lf.f); if (c == '#') { /* Unix exec. file? */ - lf.extraline = 1; while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ - if (c == '\n') c = getc(lf.f); } - if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + else if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - /* skip eventual `#!...' */ - while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; - lf.extraline = 0; + c = getc(lf.f); /* re-read first character */ } - ungetc(c, lf.f); + lf.first = c; /* 'c' is the first character of the stream */ status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ @@ -618,7 +596,7 @@ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = abs_index(L, obj); + obj = lua_absindex(L, obj); if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ return 0; lua_pushvalue(L, obj); @@ -663,13 +641,13 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { static int libsize (const luaL_Reg *l) { int size = 0; - for (; l->name; l++) size++; + for (; l && l->name; l++) size++; return size; } -LUALIB_API void luaL_register (lua_State *L, const char *libname, - const luaL_Reg *l) { +LUALIB_API void luaL_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { luaL_checkversion(L); if (libname) { /* check whether lib already exists */ @@ -685,12 +663,17 @@ LUALIB_API void luaL_register (lua_State *L, const char *libname, lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } - if (l == NULL) return; /* nothing to register? */ - for (; l->name; l++) { /* else fill the table with given functions */ - lua_pushcfunction(L, l->func); - lua_setfield(L, -2, l->name); + luaL_checkstack(L, nup, "too many upvalues"); + for (; l && l->name; l++) { /* fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); + lua_setfield(L, -(nup + 2), l->name); } + lua_pop(L, nup); /* remove upvalues */ } @@ -751,7 +734,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { - fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); return 0; /* return to Lua to abort */ } diff --git a/src/lauxlib.h b/src/lauxlib.h index b8f2e2e5..ae2e2c75 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.99 2010/01/11 16:00:45 roberto Exp $ +** $Id: lauxlib.h,v 1.105 2010/05/04 17:21:08 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -29,11 +29,11 @@ typedef struct luaL_Reg { LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); #define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) -LUALIB_API void (luaL_register) (lua_State *L, const char *libname, - const luaL_Reg *l); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); +LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); LUALIB_API int (luaL_typeerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, @@ -71,7 +71,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); -LUALIB_API int luaL_len (lua_State *L, int idx); +LUALIB_API int (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -79,9 +79,8 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level); - +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); /* @@ -111,34 +110,40 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + + /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ - - typedef struct luaL_Buffer { - char *p; /* current position in buffer */ - int lvl; /* number of strings in the stack (level) */ + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ lua_State *L; - char buffer[LUAL_BUFFERSIZE]; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ } luaL_Buffer; + #define luaL_addchar(B,c) \ - ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ - (*(B)->p++ = (char)(c))) + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) -#define luaL_addsize(B,n) ((B)->p += (n)) +#define luaL_addsize(B,s) ((B)->n += (s)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) /* }====================================================== */ diff --git a/src/lbaselib.c b/src/lbaselib.c index 162c06f2..946ecea5 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.235 2009/12/28 16:30:31 roberto Exp $ +** $Id: lbaselib.c,v 1.243 2010/04/19 17:02:02 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -23,7 +23,7 @@ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; - lua_getfield(L, LUA_ENVIRONINDEX, "tostring"); + lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; size_t l; @@ -107,50 +107,12 @@ static int luaB_setmetatable (lua_State *L) { } - -#if defined(LUA_COMPAT_FENV) - -static void getfunc (lua_State *L, int opt) { - if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); - else { - lua_Debug ar; - int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); - luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); - if (lua_getstack(L, level, &ar) == 0) - luaL_argerror(L, 1, "invalid level"); - lua_getinfo(L, "f", &ar); - } -} - -static int luaB_getfenv (lua_State *L) { - getfunc(L, 1); - if (lua_iscfunction(L, -1)) /* is a C function? */ - lua_pushglobaltable(L); /* return the global env. */ - else - lua_getfenv(L, -1); - return 1; -} - -static int luaB_setfenv (lua_State *L) { - luaL_checktype(L, 2, LUA_TTABLE); - getfunc(L, 0); - lua_pushvalue(L, 2); - if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) - return luaL_error(L, - LUA_QL("setfenv") " cannot change environment of given object"); - return 1; -} - -#else - static int luaB_getfenv (lua_State *L) { return luaL_error(L, "getfenv/setfenv deprecated"); } #define luaB_setfenv luaB_getfenv -#endif - static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); @@ -178,18 +140,13 @@ static int luaB_rawset (lua_State *L) { } -static int luaB_gcinfo (lua_State *L) { - lua_pushinteger(L, lua_gc(L, LUA_GCCOUNT, 0)); - return 1; -} - - static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", "isrunning", NULL}; + "count", "step", "setpause", "setstepmul", "isrunning", + "gen", "inc", 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 = luaL_optint(L, 2, 0); int res = lua_gc(L, o, ex); @@ -219,10 +176,11 @@ static int luaB_type (lua_State *L) { } -static int pairsmeta (lua_State *L, const char *method, int iszero) { +static int pairsmeta (lua_State *L, const char *method, int iszero, + lua_CFunction iter) { if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ - lua_pushvalue(L, lua_upvalueindex(1)); /* will return generator, */ + lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ if (iszero) lua_pushinteger(L, 0); /* and initial value */ else lua_pushnil(L); @@ -248,10 +206,12 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { - return pairsmeta(L, "__pairs", 0); + return pairsmeta(L, "__pairs", 0, luaB_next); } +#if defined(LUA_COMPAT_IPAIRS) + static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); @@ -263,9 +223,17 @@ static int ipairsaux (lua_State *L) { static int luaB_ipairs (lua_State *L) { - return pairsmeta(L, "__ipairs", 1); + return pairsmeta(L, "__ipairs", 1, ipairsaux); +} + +#else + +static int luaB_ipairs (lua_State *L) { + return luaL_error(L, "'ipairs' deprecated"); } +#endif + static int load_aux (lua_State *L, int status) { if (status == LUA_OK) @@ -376,7 +344,7 @@ static int luaB_loadin (lua_State *L) { n = luaB_load_aux(L, 2); if (n == 1) { /* success? */ lua_pushvalue(L, 1); /* environment for loaded function */ - lua_setfenv(L, -2); + lua_setupvalue(L, -2, 1); } return n; } @@ -507,14 +475,15 @@ static const luaL_Reg base_funcs[] = { {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, - {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, {"loadin", luaB_loadin}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, + {"pairs", luaB_pairs}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, @@ -668,25 +637,15 @@ static const luaL_Reg co_funcs[] = { /* }====================================================== */ -static void auxopen (lua_State *L, const char *name, - lua_CFunction f, lua_CFunction u) { - lua_pushcfunction(L, u); - lua_pushcclosure(L, f, 1); - lua_setfield(L, -2, name); -} - - static void base_open (lua_State *L) { /* set global _G */ lua_pushglobaltable(L); - lua_setfield(L, LUA_ENVIRONINDEX, "_G"); + lua_pushglobaltable(L); + lua_setfield(L, -2, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, LUA_ENVIRONINDEX, "_VERSION"); /* set global _VERSION */ - /* `ipairs' and `pairs' need auxiliary functions as upvalues */ - auxopen(L, "ipairs", luaB_ipairs, ipairsaux); - auxopen(L, "pairs", luaB_pairs, luaB_next); + lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ /* `newproxy' needs a weaktable as upvalue */ lua_createtable(L, 0, 1); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ @@ -694,7 +653,7 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setfield(L, LUA_ENVIRONINDEX, "newproxy"); /* set global `newproxy' */ + lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ } diff --git a/src/lbitlib.c b/src/lbitlib.c index 1d5a2642..b367d0c6 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.3 2010/01/12 19:40:02 roberto Exp $ +** $Id: lbitlib.c,v 1.4 2010/02/11 15:55:29 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -80,9 +80,8 @@ static int b_not (lua_State *L) { } -static int b_shift (lua_State *L) { +static int b_shift (lua_State *L, int i) { b_uint r = getuintarg(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); if (i < 0) { /* shift right? */ i = -i; if (i >= NBITS) r = 0; @@ -97,9 +96,18 @@ static int b_shift (lua_State *L) { } -static int b_rotate (lua_State *L) { +static int b_lshift (lua_State *L) { + return b_shift(L, luaL_checkint(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, -luaL_checkint(L, 2)); +} + + +static int b_rot (lua_State *L, int i) { b_uint r = getuintarg(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); i &= (NBITS - 1); /* i = i % NBITS */ r = (r << i) | (r >> (NBITS - i)); lua_pushnumber(L, lua_uint2number(r)); @@ -107,14 +115,26 @@ static int b_rotate (lua_State *L) { } +static int b_rol (lua_State *L) { + return b_rot(L, luaL_checkint(L, 2)); +} + + +static int b_ror (lua_State *L) { + return b_rot(L, -luaL_checkint(L, 2)); +} + + static const luaL_Reg bitlib[] = { {"band", b_and}, {"btest", b_test}, {"bor", b_or}, {"bxor", b_xor}, {"bnot", b_not}, - {"bshift", b_shift}, - {"brotate", b_rotate}, + {"lshift", b_lshift}, + {"rshift", b_rshift}, + {"rol", b_rol}, + {"ror", b_ror}, {NULL, NULL} }; diff --git a/src/lcode.c b/src/lcode.c index c55ebd54..d060b5f0 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.43 2010/01/11 17:38:30 roberto Exp $ +** $Id: lcode.c,v 2.46 2010/04/17 12:46:32 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -372,11 +372,6 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOCABLE; break; } - case VGLOBAL: { - e->u.s.info = luaK_codeABxX(fs, OP_GETGLOBAL, 0, e->u.s.info); - e->k = VRELOCABLE; - break; - } case VINDEXED: { freereg(fs, e->u.s.aux); freereg(fs, e->u.s.info); @@ -384,6 +379,12 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOCABLE; break; } + case VINDEXEDUP: { + freereg(fs, e->u.s.aux); + e->u.s.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.s.info, e->u.s.aux); + e->k = VRELOCABLE; + break; + } case VVARARG: case VCALL: { luaK_setoneret(fs, e); @@ -493,6 +494,12 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { } +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); +} + + void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); @@ -543,16 +550,16 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } - case VGLOBAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABxX(fs, OP_SETGLOBAL, e, var->u.s.info); - break; - } case VINDEXED: { int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } + case VINDEXEDUP: { + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OP_SETTABUP, var->u.s.info, var->u.s.aux, e); + break; + } default: { lua_assert(0); /* invalid var kind to store */ break; @@ -567,9 +574,9 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { luaK_exp2anyreg(fs, e); freeexp(fs, e); func = fs->freereg; - luaK_reserveregs(fs, 2); luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); freeexp(fs, key); + luaK_reserveregs(fs, 2); e->u.s.info = func; e->k = VNONRELOC; } @@ -695,8 +702,9 @@ static void codenot (FuncState *fs, expdesc *e) { void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + lua_assert(!hasjumps(t)); t->u.s.aux = luaK_exp2RK(fs, k); - t->k = VINDEXED; + t->k = (t->k == VUPVAL) ? VINDEXEDUP : VINDEXED; } @@ -711,7 +719,8 @@ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { } -static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { +static void codearith (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { if (constfolding(op, e1, e2)) return; else { @@ -727,6 +736,7 @@ static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { } e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; + luaK_fixline(fs, line); } } @@ -747,7 +757,7 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, } -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { expdesc e2; e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { @@ -756,14 +766,14 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ else { luaK_exp2anyreg(fs, e); - codearith(fs, OP_UNM, e, &e2); + codearith(fs, OP_UNM, e, &e2, line); } break; } case OPR_NOT: codenot(fs, e); break; case OPR_LEN: { luaK_exp2anyreg(fs, e); /* cannot operate on constants */ - codearith(fs, OP_LEN, e, &e2); + codearith(fs, OP_LEN, e, &e2, line); break; } default: lua_assert(0); @@ -798,7 +808,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } -void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { +void luaK_posfix (FuncState *fs, BinOpr op, + expdesc *e1, expdesc *e2, int line) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ @@ -824,13 +835,13 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codearith(fs, OP_CONCAT, e1, e2); + codearith(fs, OP_CONCAT, e1, e2, line); } break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { - codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2); + codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); break; } case OPR_EQ: case OPR_LT: case OPR_LE: { diff --git a/src/lcode.h b/src/lcode.h index 8ef67e55..d7f7dd62 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.52 2009/09/23 20:33:05 roberto Exp $ +** $Id: lcode.h,v 1.54 2010/04/17 12:46:32 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -57,6 +57,7 @@ LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); @@ -72,9 +73,10 @@ LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); -LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); -LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, + expdesc *v2, int line); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); diff --git a/src/ldblib.c b/src/ldblib.c index eeaedc1f..28e671df 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.119 2010/01/06 14:42:35 roberto Exp $ +** $Id: ldblib.c,v 1.121 2010/03/26 20:58:11 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -44,19 +44,19 @@ static int db_setmetatable (lua_State *L) { } -static int db_getfenv (lua_State *L) { - luaL_checkany(L, 1); - lua_getfenv(L, 1); +static int db_getenv (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + lua_getenv(L, 1); return 1; } -static int db_setfenv (lua_State *L) { - luaL_checktype(L, 2, LUA_TTABLE); +static int db_setenv (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + if (!lua_isnoneornil(L, 2)) + luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); - if (lua_setfenv(L, 1) == 0) - luaL_error(L, LUA_QL("setfenv") - " cannot change environment of given object"); + lua_setenv(L, 1); return 1; } @@ -339,15 +339,13 @@ static int db_gethook (lua_State *L) { static int db_debug (lua_State *L) { for (;;) { char buffer[250]; - fputs("lua_debug> ", stderr); + luai_writestringerror("%s", "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || - lua_pcall(L, 0, 0, 0)) { - fputs(lua_tostring(L, -1), stderr); - fputs("\n", stderr); - } + lua_pcall(L, 0, 0, 0)) + luai_writestringerror("%s\n", lua_tostring(L, -1)); lua_settop(L, 0); /* remove eventual returns */ } } @@ -369,7 +367,7 @@ static int db_traceback (lua_State *L) { static const luaL_Reg dblib[] = { {"debug", db_debug}, - {"getfenv", db_getfenv}, + {"getenv", db_getenv}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, @@ -378,7 +376,7 @@ static const luaL_Reg dblib[] = { {"getupvalue", db_getupvalue}, {"upvaluejoin", db_upvaluejoin}, {"upvalueid", db_upvalueid}, - {"setfenv", db_setfenv}, + {"setenv", db_setenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, diff --git a/src/ldebug.c b/src/ldebug.c index 2544a5dd..dcc8ca99 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.63 2010/01/13 16:18:25 roberto Exp $ +** $Id: ldebug.c,v 2.70 2010/04/13 20:48:12 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -144,7 +144,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (cl->c.isC) { + if (cl == NULL || cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; @@ -191,8 +191,8 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'u': { - ar->nups = f->c.nupvalues; - if (f->c.isC) { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (f == NULL || f->c.isC) { ar->isvararg = 1; ar->nparams = 0; } @@ -226,28 +226,30 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; - Closure *f = NULL; - CallInfo *ci = NULL; + Closure *cl; + CallInfo *ci; + StkId func; lua_lock(L); if (*what == '>') { - StkId func = L->top - 1; + ci = NULL; + func = L->top - 1; luai_apicheck(L, ttisfunction(func)); what++; /* skip the '>' */ - f = clvalue(func); L->top--; /* pop function */ } else { ci = ar->i_ci; + func = ci->func; lua_assert(ttisfunction(ci->func)); - f = clvalue(ci->func); } - status = auxgetinfo(L, what, ar, f, ci); + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { - setclvalue(L, L->top, f); + setobjs2s(L, L->top, func); incr_top(L); } if (strchr(what, 'L')) - collectvalidlines(L, f); + collectvalidlines(L, cl); lua_unlock(L); return status; } @@ -260,22 +262,23 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { */ -static const char *kname (Proto *p, int c) { - if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) - return svalue(&p->k[INDEXK(c)]); +static void kname (Proto *p, int c, int reg, const char *what, + const char **name) { + if (c == reg && *what == 'c') + return; /* index is a constant; name already correct */ + else if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + *name = svalue(&p->k[INDEXK(c)]); else - return "?"; + *name = "?"; } static const char *getobjname (lua_State *L, CallInfo *ci, int reg, const char **name) { - Proto *p; - int lastpc, pc; + Proto *p = ci_func(ci)->l.p; const char *what = NULL; - lua_assert(isLua(ci)); - p = ci_func(ci)->l.p; - lastpc = currentpc(ci); + int lastpc = currentpc(ci); + int pc; *name = luaF_getlocalname(p, reg + 1, lastpc); if (*name) /* is a local? */ return "local"; @@ -285,17 +288,6 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, OpCode op = GET_OPCODE(i); int a = GETARG_A(i); switch (op) { - case OP_GETGLOBAL: { - if (reg == a) { - int g = GETARG_Bx(i); - if (g != 0) g--; - else g = GETARG_Ax(p->code[++pc]); - lua_assert(ttisstring(&p->k[g])); - *name = svalue(&p->k[g]); - what = "global"; - } - break; - } case OP_MOVE: { if (reg == a) { int b = GETARG_B(i); /* move from 'b' to 'a' */ @@ -305,11 +297,16 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, } break; } + case OP_GETTABUP: case OP_GETTABLE: { if (reg == a) { int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - what = "field"; + int t = GETARG_B(i); + const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ + ? luaF_getlocalname(p, t + 1, pc) + : getstr(p->upvalues[t].name); + kname(p, k, a, what, name); + what = (vn && strcmp(vn, "_ENV") == 0) ? "global" : "field"; } break; } @@ -322,6 +319,17 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, } break; } + case OP_LOADK: { + if (reg == a) { + int b = GETARG_Bx(i); + b = (b > 0) ? b - 1 : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + what = "constant"; + *name = svalue(&p->k[b]); + } + } + break; + } case OP_LOADNIL: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */ @@ -331,7 +339,7 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, case OP_SELF: { if (reg == a) { int k = GETARG_C(i); /* key index */ - *name = kname(p, k); + kname(p, k, a, what, name); what = "method"; } break; @@ -374,12 +382,15 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: - case OP_TFORLOOP: return getobjname(L, ci, GETARG_A(i), name); - case OP_GETGLOBAL: + case OP_TFORCALL: { + *name = "for iterator"; + return "for iterator"; + } case OP_SELF: + case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; - case OP_SETGLOBAL: + case OP_SETTABUP: case OP_SETTABLE: tm = TM_NEWINDEX; break; case OP_EQ: tm = TM_EQ; break; case OP_ADD: tm = TM_ADD; break; @@ -413,13 +424,30 @@ static int isinstack (CallInfo *ci, const TValue *o) { } +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = &ci_func(ci)->l; + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v == o) { + *name = getstr(c->p->upvalues[i].name); + return "upvalue"; + } + } + return NULL; +} + + void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { CallInfo *ci = L->ci; const char *name = NULL; - const char *t = typename(ttype(o)); - const char *kind = (isLua(ci) && isinstack(ci, o)) ? - getobjname(L, ci, cast_int(o - ci->u.l.base), &name) : - NULL; + const char *t = objtypename(o); + const char *kind = NULL; + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind && isinstack(ci, o)) /* no? try a register */ + kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name); + } if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); @@ -444,8 +472,8 @@ void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = typename(ttype(p1)); - const char *t2 = typename(ttype(p2)); + const char *t1 = objtypename(p1); + const char *t2 = objtypename(p2); if (t1 == t2) luaG_runerror(L, "attempt to compare two %s values", t1); else @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.80 2010/01/13 16:17:32 roberto Exp $ +** $Id: ldo.c,v 2.87 2010/05/05 18:49:56 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -48,7 +48,7 @@ */ #if !defined(LUAI_THROW) -#if defined(__cplusplus) +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ @@ -83,8 +83,8 @@ struct lua_longjmp { static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { - case LUA_ERRMEM: { - setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } case LUA_ERRERR: { @@ -293,18 +293,43 @@ static StkId tryfuncTM (lua_State *L, StkId func) { ** returns true if function has been executed (C function) */ int luaD_precall (lua_State *L, StkId func, int nresults) { - LClosure *cl; + Closure *cl; + lua_CFunction f; ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); - cl = &clvalue(func)->l; L->ci->nresults = nresults; - if (!cl->isC) { /* Lua function? prepare its call */ + if (ttislcf(func)) { /* light C function? */ + f = fvalue(func); /* get it */ + goto isCfunc; /* go to call it */ + } + cl = clvalue(func); + if (cl->c.isC) { /* C closure? */ + CallInfo *ci; + int n; + f = cl->c.f; + isCfunc: /* call C function 'f' */ + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = next_ci(L); /* now 'enter' new function */ + ci->func = restorestack(L, funcr); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; + if (L->hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, L->top - n); + return 1; + } + else { /* Lua function: prepare its call */ CallInfo *ci; int nparams, nargs; StkId base; - Proto *p = cl->p; + Proto *p = cl->l.p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); nargs = cast_int(L->top - func) - 1; /* number of real arguments */ @@ -327,24 +352,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { callhook(L, ci); return 0; } - else { /* if is a C function, call it */ - CallInfo *ci; - int n; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = next_ci(L); /* now 'enter' new function */ - ci->func = restorestack(L, funcr); - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); - lua_unlock(L); - n = (*curr_func(L)->c.f)(L); /* do the actual call */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, L->top - n); - return 1; - } } @@ -452,7 +459,7 @@ static int recover (lua_State *L, int status) { CallInfo *ci = findpcall(L); if (ci == NULL) return 0; /* no recovery point */ /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->u.c.oldtop); + oldtop = restorestack(L, ci->u.c.extra); luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; @@ -469,7 +476,7 @@ static int recover (lua_State *L, int status) { /* ** signal an error in the call to 'resume', not in the execution of the ** coroutine itself. (Such errors should not be handled by any coroutine -** error hanlder and should not kill the coroutine.) +** error handler and should not kill the coroutine.) */ static void resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ @@ -501,11 +508,11 @@ static void resume (lua_State *L, void *ud) { if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ + ci->func = restorestack(L, ci->u.c.extra); if (ci->u.c.k != NULL) { /* does it have a continuation? */ int n; ci->u.c.status = LUA_YIELD; /* 'default' status */ ci->callstatus |= CIST_YIELDED; - ci->func = restorestack(L, ci->u.c.oldtop); lua_unlock(L); n = (*ci->u.c.k)(L); /* call continuation */ lua_lock(L); @@ -526,6 +533,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { luai_userstateresume(L, nargs); ++G(L)->nCcalls; /* count resume */ L->nny = 0; /* allow yields */ + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status == -1) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; @@ -565,11 +573,10 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { api_check(L, k == NULL, "hooks cannot continue after yielding"); } else { - if ((ci->u.c.k = k) != NULL) { /* is there a continuation? */ + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ ci->u.c.ctx = ctx; /* save context */ - ci->u.c.oldtop = savestack(L, ci->func); /* save current 'func' */ - } - ci->func = L->top - nresults - 1; /* protect stack slots below */ + ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */ + ci->func = L->top - nresults - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ @@ -623,7 +630,7 @@ static void f_parser (lua_State *L, void *ud) { : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); setptvalue2s(L, L->top, tf); incr_top(L); - cl = luaF_newLclosure(L, tf->sizeupvalues, G(L)->l_gt); + cl = luaF_newLclosure(L, tf->sizeupvalues); cl->l.p = tf; setclvalue(L, L->top - 1, cl); for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ diff --git a/src/ldump.c b/src/ldump.c index f95381ab..b2c1e709 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ +** $Id: ldump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -145,7 +145,6 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); - DumpChar(f->envreg,D); DumpCode(f,D); DumpConstants(f,D); DumpUpvalues(f,D); diff --git a/src/lfunc.c b/src/lfunc.c index afc097c6..e95dad01 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.19 2009/12/16 16:42:58 roberto Exp $ +** $Id: lfunc.c,v 2.24 2010/05/10 18:23:45 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -21,19 +21,17 @@ -Closure *luaF_newCclosure (lua_State *L, int n, Table *e) { +Closure *luaF_newCclosure (lua_State *L, int n) { Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl; c->c.isC = 1; - c->c.env = e; c->c.nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, int n, Table *e) { +Closure *luaF_newLclosure (lua_State *L, int n) { Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; c->l.isC = 0; - c->l.env = e; c->l.nupvalues = cast_byte(n); while (n--) c->l.upvals[n] = NULL; return c; @@ -54,12 +52,14 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { UpVal *p; UpVal *uv; while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { + GCObject *o = obj2gco(p); lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ - if (isdead(g, obj2gco(p))) /* is it dead? */ - changewhite(obj2gco(p)); /* ressurrect it */ + if (isdead(g, o)) /* is it dead? */ + changewhite(o); /* ressurrect it */ return p; } + resetoldbit(o); /* may create a newer upval after this one */ pp = &p->next; } /* not found: create a new one */ @@ -98,10 +98,12 @@ void luaF_close (lua_State *L, StkId level) { if (isdead(g, o)) luaF_freeupval(L, uv); /* free upvalue */ else { - unlinkupval(uv); - setobj(L, &uv->u.value, uv->v); + unlinkupval(uv); /* remove upvalue from 'uvhead' list */ + setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ uv->v = &uv->u.value; /* now current value lives here */ - luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ + g->allgc = o; + luaC_checkupvalcolor(g, uv); } } } @@ -127,7 +129,6 @@ Proto *luaF_newproto (lua_State *L) { f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; - f->envreg = NO_REG; return f; } diff --git a/src/lfunc.h b/src/lfunc.h index 2e02419b..d11182b0 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ +** $Id: lfunc.h,v 2.5 2010/03/26 20:58:11 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -19,8 +19,8 @@ LUAI_FUNC Proto *luaF_newproto (lua_State *L); -LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.67 2009/12/22 15:32:50 roberto Exp $ +** $Id: lgc.c,v 2.96 2010/05/17 20:39:31 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -23,21 +23,49 @@ #include "ltm.h" -#define GCSTEPSIZE 1024u + +/* how much to allocate before next GC step */ +#define GCSTEPSIZE 1024 + +/* maximum numer of elements to sweep in each single step */ #define GCSWEEPMAX 40 -#define GCSWEEPCOST 10 -#define GCFINALIZECOST 100 +/* cost of sweeping one element */ +#define GCSWEEPCOST 1 + +/* maximum number of finalizers to call in each GC step */ +#define GCFINALIZENUM 4 + +/* cost of marking the root set */ +#define GCROOTCOST 10 + +/* cost of atomic step */ +#define GCATOMICCOST 1000 + +/* basic cost to traverse one object (to be added to the links the + object may have) */ +#define TRAVCOST 5 -#define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) +/* +** standard negative debt for GC; a reasonable "time" to wait before +** starting a new cycle +*/ +#define stddebt(g) (-cast(l_mem, g->totalbytes/100) * g->gcpause) + + +/* +** 'makewhite' erases all color bits plus the old bit and then +** sets only the current white bit +*/ +#define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS)) #define makewhite(g,x) \ (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) -#define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS) +#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS))) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) @@ -51,7 +79,6 @@ #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } - static void reallymarkobject (global_State *g, GCObject *o); @@ -61,12 +88,16 @@ static void reallymarkobject (global_State *g, GCObject *o); ** ======================================================= */ -static void linktable (Table *h, GCObject **p) { - h->gclist = *p; - *p = obj2gco(h); -} + +/* +** link table 'h' into list pointed by 'p' +*/ +#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) +/* +** mark a table entry as dead (therefore removing it from the table) +*/ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) @@ -75,8 +106,8 @@ static void removeentry (Node *n) { /* -** The next function tells whether a key or value can be cleared from -** a weak table. Non-collectable objects are never removed from weak +** tells whether a key or value can be cleared from a weak +** table. Non-collectable objects are never removed from weak ** tables. Strings behave as `values', so are never removed too. for ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values @@ -92,24 +123,32 @@ static int iscleared (const TValue *o, int iskey) { } +/* +** barrier that moves collector forward, that is, mark the white object +** being pointed by a black object. +*/ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(isgenerational(g) || g->gcstate != GCSpause); lua_assert(gch(o)->tt != LUA_TTABLE); - /* must keep invariant? */ - if (g->gcstate == GCSpropagate) + if (keepinvariant(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ - makewhite(g, o); /* mark as white just to avoid other barriers */ + else { /* sweep phase */ + lua_assert(issweepphase(g)); + makewhite(g, o); /* mark main obj. as white to avoid other barriers */ + } } +/* +** barrier that moves collector backward, that is, mark the black object +** pointing to a white object as gray again. +*/ void luaC_barrierback (lua_State *L, Table *t) { global_State *g = G(L); GCObject *o = obj2gco(t); lua_assert(isblack(o) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ t->gclist = g->grayagain; g->grayagain = o; @@ -117,14 +156,37 @@ void luaC_barrierback (lua_State *L, Table *t) { /* -** create a new collectable object and link it to '*list' +** check color (and invariants) for an upvalue that was closed, +** i.e., moved into the 'allgc' list +*/ +void luaC_checkupvalcolor (global_State *g, UpVal *uv) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o)); /* open upvalues are never black */ + if (isgray(o)) { + if (keepinvariant(g)) { + resetoldbit(o); /* see MOVE OLD rule */ + gray2black(o); /* it is being visited now */ + markvalue(g, uv->v); + } + else { + lua_assert(issweepphase(g)); + makewhite(g, o); + } + } +} + + +/* +** create a new collectable object (with given type and size) and link +** it to '*list'. 'offset' tells how many bytes to allocate before the +** object itself (used only by states). */ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset) { global_State *g = G(L); GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); if (list == NULL) - list = &g->rootgc; /* standard list for collectable objects */ + list = &g->allgc; /* standard list for collectable objects */ gch(o)->marked = luaC_white(g); gch(o)->tt = tt; gch(o)->next = *list; @@ -132,24 +194,6 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, return o; } - -void luaC_linkupval (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = obj2gco(uv); - gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ - g->rootgc = o; - if (isgray(o)) { - if (g->gcstate == GCSpropagate) { - gray2black(o); /* closed upvalues need barrier */ - luaC_barrier(L, uv, uv->v); - } - else { /* sweep phase: sweep it (turning it into white) */ - makewhite(g, o); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - } - } -} - /* }====================================================== */ @@ -160,25 +204,33 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { ** ======================================================= */ + +/* +** mark an object. Userdata and closed upvalues are visited and turned +** black here. Strings remain gray (it is the same as making them +** black). Other objects are marked gray and added to appropriate list +** to be visited (and turned black) later. (Open upvalues are already +** linked in 'headuv' list.) +*/ static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); white2gray(o); switch (gch(o)->tt) { case LUA_TSTRING: { - return; + return; /* for strings, gray is as good as black */ } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; - gray2black(o); /* udata are never gray */ markobject(g, mt); markobject(g, gco2u(o)->env); + gray2black(o); /* all pointers marked */ return; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); - if (uv->v == &uv->u.value) /* closed? */ - gray2black(o); /* open upvalues are never black */ + if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */ + gray2black(o); /* make it black */ return; } case LUA_TFUNCTION: { @@ -205,48 +257,55 @@ static void reallymarkobject (global_State *g, GCObject *o) { } +/* +** mark tag methods for basic types +*/ static void markmt (global_State *g) { int i; - for (i=0; i<NUM_TAGS; i++) + for (i=0; i < LUA_NUMTAGS; i++) markobject(g, g->mt[i]); } +/* +** mark all objects in list of being-finalized +*/ static void markbeingfnz (global_State *g) { GCObject *o; for (o = g->tobefnz; o != NULL; o = gch(o)->next) { - lua_assert(testbit(gch(o)->marked, SEPARATED)); makewhite(g, o); reallymarkobject(g, o); } } -/* mark root set */ -static void markroot (lua_State *L) { - global_State *g = G(L); - g->gray = NULL; - g->grayagain = NULL; - g->weak = g->ephemeron = g->allweak = NULL; - markobject(g, g->mainthread); - /* make global table and registry to be traversed before main stack */ - markobject(g, g->l_gt); - markvalue(g, &g->l_registry); - markmt(g); - markbeingfnz(g); /* mark any finalizing object left from previous cycle */ - g->gcstate = GCSpropagate; -} - - +/* +** mark all values stored in marked open upvalues. (See comment in +** 'lstate.h'.) +*/ static void remarkupvals (global_State *g) { UpVal *uv; for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); if (isgray(obj2gco(uv))) markvalue(g, uv->v); } } + +/* +** mark root set and reset all gray lists, to start a new +** incremental (or full) collection +*/ +static void markroot (lua_State *L) { + global_State *g = G(L); + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +} + /* }====================================================== */ @@ -257,49 +316,48 @@ static void remarkupvals (global_State *g) { */ static void traverseweakvalue (global_State *g, Table *h) { - int i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + Node *n, *limit = gnode(h, sizenode(h)); + for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); - if (ttisnil(gval(n))) - removeentry(n); /* remove empty entries */ + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); + markvalue(g, gkey(n)); /* mark key */ } } - linktable(h, &g->weak); + linktable(h, &g->weak); /* link into appropriate list */ } static int traverseephemeron (global_State *g, Table *h) { - int marked = 0; - int hasclears = 0; - int i = h->sizearray; - while (i--) { /* mark array part (numeric keys are 'strong') */ + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has unmarked pairs */ + Node *n, *limit = gnode(h, sizenode(h)); + int i; + /* traverse array part (numeric keys are 'strong') */ + for (i = 0; i < h->sizearray; i++) { if (valiswhite(&h->array[i])) { marked = 1; reallymarkobject(g, gcvalue(&h->array[i])); } } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + /* traverse hash part */ + for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ - else if (valiswhite(gval(n))) { - /* value is not marked yet */ + else if (valiswhite(gval(n))) { /* value not marked yet? */ if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ hasclears = 1; /* may have to propagate mark from key to value */ - else { /* mark value only if key is marked */ - marked = 1; /* some mark changed status */ + else { /* key is marked, so mark value */ + marked = 1; /* value was not marked */ reallymarkobject(g, gcvalue(gval(n))); } } } - if (hasclears) - linktable(h, &g->ephemeron); + if (hasclears) /* does table have unmarked pairs? */ + linktable(h, &g->ephemeron); /* will have to propagate again */ else /* nothing to propagate */ linktable(h, &g->weak); /* avoid convergence phase */ return marked; @@ -307,26 +365,24 @@ static int traverseephemeron (global_State *g, Table *h) { static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnode(h, sizenode(h)); int i; - i = h->sizearray; - while (i--) + for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); - if (ttisnil(gval(n))) - removeentry(n); /* remove empty entries */ + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); - markvalue(g, gval(n)); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ } } } -static void traversetable (global_State *g, Table *h) { +static int traversetable (global_State *g, Table *h) { const TValue *mode = gfasttm(g, h->metatable, TM_MODE); markobject(g, h->metatable); if (mode && ttisstring(mode)) { /* is there a weak mode? */ @@ -334,43 +390,41 @@ static void traversetable (global_State *g, Table *h) { int weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ black2gray(obj2gco(h)); /* keep table gray */ - if (!weakkey) /* strong keys? */ + if (!weakkey) { /* strong keys? */ traverseweakvalue(g, h); - else if (!weakvalue) /* strong values? */ + return TRAVCOST + sizenode(h); + } + else if (!weakvalue) { /* strong values? */ traverseephemeron(g, h); - else + return TRAVCOST + h->sizearray + sizenode(h); + } + else { linktable(h, &g->allweak); /* nothing to traverse now */ - return; + return TRAVCOST; + } } /* else go through */ } traversestrongtable(g, h); + return TRAVCOST + h->sizearray + (2 * sizenode(h)); } -/* -** All marks are conditional because a GC may happen while the -** prototype is still being created -*/ -static void traverseproto (global_State *g, Proto *f) { +static int traverseproto (global_State *g, Proto *f) { int i; - if (f->source) stringmark(f->source); - for (i=0; i<f->sizek; i++) /* mark literals */ + stringmark(f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); - for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ - if (f->upvalues[i].name) - stringmark(f->upvalues[i].name); - } - for (i=0; i<f->sizep; i++) /* mark nested protos */ + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + stringmark(f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ markobject(g, f->p[i]); - for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ - if (f->locvars[i].varname) - stringmark(f->locvars[i].varname); - } + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + stringmark(f->locvars[i].varname); + return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; } -static void traverseclosure (global_State *g, Closure *cl) { - markobject(g, cl->c.env); +static l_mem traverseclosure (global_State *g, Closure *cl) { if (cl->c.isC) { int i; for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ @@ -379,32 +433,35 @@ static void traverseclosure (global_State *g, Closure *cl) { else { int i; lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); - markobject(g, cl->l.p); + markobject(g, cl->l.p); /* mark its prototype */ for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); } + return TRAVCOST + cl->c.nupvalues; } -static void traversestack (global_State *g, lua_State *L) { - StkId o; - if (L->stack == NULL) - return; /* stack not completely built yet */ - for (o = L->stack; o < L->top; o++) +static int traversestack (global_State *g, lua_State *L) { + StkId o = L->stack; + if (o == NULL) + return 1; /* stack not completely built yet */ + for (; o < L->top; o++) markvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ StkId lim = L->stack + L->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } + return TRAVCOST + cast_int(o - L->stack); } /* -** traverse one gray object, turning it to black. -** Returns `quantity' traversed. +** traverse one gray object, turning it to black (except for threads, +** which are always gray). +** Returns number of values traversed. */ -static l_mem propagatemark (global_State *g) { +static int propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); @@ -412,16 +469,12 @@ static l_mem propagatemark (global_State *g) { case LUA_TTABLE: { Table *h = gco2t(o); g->gray = h->gclist; - traversetable(g, h); - return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * sizenode(h); + return traversetable(g, h); } case LUA_TFUNCTION: { Closure *cl = gco2cl(o); g->gray = cl->c.gclist; - traverseclosure(g, cl); - return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : - sizeLclosure(cl->l.nupvalues); + return traverseclosure(g, cl); } case LUA_TTHREAD: { lua_State *th = gco2th(o); @@ -429,19 +482,12 @@ static l_mem propagatemark (global_State *g) { th->gclist = g->grayagain; g->grayagain = o; black2gray(o); - traversestack(g, th); - return sizeof(lua_State) + sizeof(TValue) * th->stacksize; + return traversestack(g, th); } case LUA_TPROTO: { Proto *p = gco2p(o); g->gray = p->gclist; - traverseproto(g, p); - return sizeof(Proto) + sizeof(Instruction) * p->sizecode + - sizeof(Proto *) * p->sizep + - sizeof(TValue) * p->sizek + - sizeof(int) * p->sizelineinfo + - sizeof(LocVar) * p->sizelocvars + - sizeof(TString *) * p->sizeupvalues; + return traverseproto(g, p); } default: lua_assert(0); return 0; } @@ -465,14 +511,14 @@ static void convergeephemerons (global_State *g) { int changed; do { GCObject *w; - GCObject *next = g->ephemeron; - g->ephemeron = NULL; + GCObject *next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables will return to this list when traversed */ changed = 0; while ((w = next) != NULL) { next = gco2t(w)->gclist; - if (traverseephemeron(g, gco2t(w))) { - changed = 1; - propagateall(g); + if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ } } } while (changed); @@ -487,26 +533,26 @@ static void convergeephemerons (global_State *g) { ** ======================================================= */ -/* clear collected entries from weaktables */ +/* +** clear collected entries from all weaktables in list 'l' +*/ static void cleartable (GCObject *l) { - while (l) { + for (; l != NULL; l = gco2t(l)->gclist) { Table *h = gco2t(l); - int i = h->sizearray; - while (i--) { + Node *n, *limit = gnode(h, sizenode(h)); + int i; + for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(o, 0)) /* value was collected? */ setnilvalue(o); /* remove value */ } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && /* non-empty entry? */ (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* remove entry from table */ + removeentry(n); /* and remove entry from table */ } } - l = h->gclist; } } @@ -533,33 +579,63 @@ static void freeobj (lua_State *L, GCObject *o) { static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); -static void sweepthread (lua_State *L, lua_State *L1, int alive) { +/* +** sweep the (open) upvalues of a thread and resize its stack and +** list of call-info structures. +*/ +static void sweepthread (lua_State *L, lua_State *L1) { if (L1->stack == NULL) return; /* stack not completely built yet */ sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ luaE_freeCI(L1); /* free extra CallInfo slots */ /* should not change the stack during an emergency gc cycle */ - if (alive && G(L)->gckind != KGC_EMERGENCY) + if (G(L)->gckind != KGC_EMERGENCY) luaD_shrinkstack(L1); } +/* +** sweep at most 'count' elements from a list of GCObjects erasing dead +** objects, where a dead (not alive) object is one marked with the "old" +** (non current) white and not fixed. +** In non-generational mode, change all non-dead objects back to white, +** preparing for next collection cycle. +** In generational mode, keep black objects black, and also mark them as +** old; stop when hitting an old object, as all objects after that +** one will be old too. +** When object is a thread, sweep its list of open upvalues too. +*/ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { - GCObject *curr; global_State *g = G(L); - int deadmask = otherwhite(g); - while ((curr = *p) != NULL && count-- > 0) { - int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; - if (gch(curr)->tt == LUA_TTHREAD) - sweepthread(L, gco2th(curr), alive); - if (alive) { - lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); - makewhite(g, curr); /* make it white (for next cycle) */ - p = &gch(curr)->next; - } - else { /* must erase `curr' */ - lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); + int ow = otherwhite(g); + int toclear, toset; /* bits to clear and to set in all live objects */ + int tostop; /* stop sweep when this is true */ + if (isgenerational(g)) { /* generational mode? */ + toclear = ~0; /* clear nothing */ + toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ + tostop = bitmask(OLDBIT); /* do not sweep old generation */ + } + else { /* normal mode */ + toclear = maskcolors; /* clear all color bits + old bit */ + toset = luaC_white(g); /* make object white */ + tostop = 0; /* do not stop */ + } + while (*p != NULL && count-- > 0) { + GCObject *curr = *p; + int marked = gch(curr)->marked; + if (isdeadm(ow, marked)) { /* is 'curr' dead? */ *p = gch(curr)->next; /* remove 'curr' from list */ - freeobj(L, curr); + freeobj(L, curr); /* erase 'curr' */ + } + else { + if (gch(curr)->tt == LUA_TTHREAD) + sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ + if (testbits(marked, tostop)) { + static GCObject *nullp = NULL; + return &nullp; /* stop sweeping this list */ + } + /* update marks */ + gch(curr)->marked = cast_byte((marked & toclear) | toset); + p = &gch(curr)->next; /* go to next element */ } } return p; @@ -576,25 +652,28 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { static void checkSizes (lua_State *L) { global_State *g = G(L); - if (g->strt.nuse < cast(lu_int32, g->strt.size)) { - /* string-table size could be the smaller power of 2 larger than 'nuse' */ - int size = 1 << luaO_ceillog2(g->strt.nuse); - if (size < g->strt.size) /* current table too large? */ - luaS_resize(L, size); /* shrink it */ + if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */ + int hs = g->strt.size / 2; /* half the size of the string table */ + if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */ + luaS_resize(L, hs); /* halve its size */ + luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ } - luaZ_freebuffer(L, &g->buff); } static Udata *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ - g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ - gch(o)->next = g->rootgc; /* return it to `root' list */ - g->rootgc = o; - lua_assert(isfinalized(gch(o))); - resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ - makewhite(g, o); - return rawgco2u(o); + Udata *u = rawgco2u(o); + lua_assert(isfinalized(&u->uv)); + lua_assert(!isold(o)); + g->tobefnz = u->uv.next; /* remove it from 'tobefnz' list */ + u->uv.next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(u->uv.marked, SEPARATED); /* mark that it is not in 'tobefnz' */ + resetoldbit(o); /* see MOVE OLD rule */ + if (!keepinvariant(g)) /* not keeping invariant? */ + makewhite(g, o); /* "sweep" object */ + return u; } @@ -608,18 +687,18 @@ static void GCTM (lua_State *L, int propagateerrors) { global_State *g = G(L); Udata *udata = udata2finalize(g); const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC); - if (tm != NULL && ttisfunction(tm)) { + if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; - lu_mem oldt = g->GCthreshold; + lu_mem oldd = g->GCdebt; L->allowhook = 0; /* stop debug hooks during GC tag method */ - g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ - setobj2s(L, L->top, tm); - setuvalue(L, L->top+1, udata); - L->top += 2; + stopgc(g); /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + setuvalue(L, L->top+1, udata); /* ... and its argument */ + L->top += 2; /* and (next line) call the finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ - g->GCthreshold = oldt; /* restore threshold */ + g->GCdebt = oldd; /* restore threshold */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status == LUA_ERRRUN) { /* is there an error msg.? */ luaO_pushfstring(L, "error in __gc tag method (%s)", @@ -632,14 +711,18 @@ static void GCTM (lua_State *L, int propagateerrors) { } -/* move 'dead' udata that need finalization to list 'tobefnz' */ +/* +** move all unreachable udata that need finalization from list 'udgc' to +** list 'tobefnz' +*/ void luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); - GCObject **p = &g->mainthread->next; + GCObject **p = &g->udgc; GCObject *curr; GCObject **lastnext = &g->tobefnz; - /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ - while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; + /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ + while (*lastnext != NULL) + lastnext = &gch(*lastnext)->next; while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr))); lua_assert(testbit(gch(curr)->marked, SEPARATED)); @@ -647,9 +730,8 @@ void luaC_separateudata (lua_State *L, int all) { p = &gch(curr)->next; /* don't bother with it */ else { l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ - *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ - /* link 'curr' at the end of 'tobefnz' list */ - gch(curr)->next = *lastnext; + *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */ + gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; lastnext = &gch(curr)->next; } @@ -657,20 +739,24 @@ void luaC_separateudata (lua_State *L, int all) { } +/* +** if userdata 'u' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'udgc' list. +*/ void luaC_checkfinalizer (lua_State *L, Udata *u) { global_State *g = G(L); - if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */ - isfinalized(&u->uv) || /* ... or is finalized... */ - gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ + if (testbit(u->uv.marked, SEPARATED) || /* udata is already separated... */ + isfinalized(&u->uv) || /* ... or is finalized... */ + gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ - else { /* move 'u' to 2nd part of root list */ + else { /* move 'u' to 'udgc' list */ GCObject **p; - for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) - lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ + for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ; *p = u->uv.next; /* remove 'u' from root list */ - u->uv.next = g->mainthread->next; /* re-link it in list */ - g->mainthread->next = obj2gco(u); + u->uv.next = g->udgc; /* link it in list 'udgc' */ + g->udgc = obj2gco(u); l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ + resetoldbit(obj2gco(u)); /* see MOVE OLD rule */ } } @@ -683,15 +769,52 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) { ** ======================================================= */ + +#define sweepphases \ + (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + +/* +** change GC mode +*/ +void luaC_changemode (lua_State *L, int mode) { + global_State *g = G(L); + if (mode == g->gckind) return; /* nothing to change */ + if (mode == KGC_GEN) { /* change to generational mode */ + /* make sure gray lists are consistent */ + luaC_runtilstate(L, bitmask(GCSpropagate)); + g->lastmajormem = g->totalbytes; + g->gckind = KGC_GEN; + } + else { /* change to incremental mode */ + /* sweep all objects to turn them back to white + (as white has not changed, nothing extra will be collected) */ + g->sweepstrgc = 0; + g->gcstate = GCSsweepstring; + g->gckind = KGC_NORMAL; + luaC_runtilstate(L, ~sweepphases); + } +} + + +/* +** call all pending finalizers */ +static void callallpendingfinalizers (lua_State *L, int propagateerrors) { + global_State *g = G(L); + while (g->tobefnz) GCTM(L, propagateerrors); +} + + void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); int i; - while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */ + callallpendingfinalizers(L, 0); /* following "white" makes all objects look dead */ - g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); - sweepwholelist(L, &g->rootgc); - lua_assert(g->rootgc == obj2gco(g->mainthread) && - g->mainthread->next == NULL); + g->currentwhite = WHITEBITS; + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->udgc); + lua_assert(g->udgc == NULL); + sweepwholelist(L, &g->allgc); + lua_assert(g->allgc == NULL); for (i = 0; i < g->strt.size; i++) /* free all string lists */ sweepwholelist(L, &g->strt.hash[i]); lua_assert(g->strt.nuse == 0); @@ -700,7 +823,6 @@ void luaC_freeallobjects (lua_State *L) { static void atomic (lua_State *L) { global_State *g = G(L); - g->gcstate = GCSatomic; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ @@ -710,12 +832,11 @@ static void atomic (lua_State *L) { remarkupvals(g); /* traverse objects caught by write barrier and by 'remarkupvals' */ propagateall(g); - /* at this point, all strongly accessible objects are marked. - Start marking weakly accessible objects. */ traverselistofgrays(g, &g->weak); /* remark weak tables */ traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ traverselistofgrays(g, &g->grayagain); /* remark gray again */ convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ luaC_separateudata(L, 0); /* separate userdata to be finalized */ markbeingfnz(g); /* mark userdata that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ @@ -724,51 +845,68 @@ static void atomic (lua_State *L) { cleartable(g->weak); cleartable(g->ephemeron); cleartable(g->allweak); - g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - g->sweepstrgc = 0; /* go to sweep phase */ + g->sweepstrgc = 0; /* prepare to sweep strings */ g->gcstate = GCSsweepstring; + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + /*lua_checkmemory(L);*/ } static l_mem singlestep (lua_State *L) { global_State *g = G(L); - /*lua_checkmemory(L);*/ switch (g->gcstate) { case GCSpause: { - markroot(L); /* start a new collection */ - return 0; + if (!isgenerational(g)) + markroot(L); /* start a new collection */ + /* in any case, root must be marked */ + lua_assert(!iswhite(obj2gco(g->mainthread)) + && !iswhite(gcvalue(&g->l_registry))); + g->gcstate = GCSpropagate; + return GCROOTCOST; } case GCSpropagate: { if (g->gray) return propagatemark(g); else { /* no more `gray' objects */ - atomic(L); /* finish mark phase */ - return 0; + g->gcstate = GCSatomic; /* finish mark phase */ + atomic(L); + return GCATOMICCOST; } } case GCSsweepstring: { - sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ - g->sweepgc = &g->rootgc; - g->gcstate = GCSsweep; /* sweep all other objects */ + if (g->sweepstrgc < g->strt.size) { + sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); + return GCSWEEPCOST; + } + else { /* no more strings to sweep */ + g->sweepgc = &g->udgc; /* prepare to sweep userdata */ + g->gcstate = GCSsweepudata; + return 0; } - return GCSWEEPCOST; } - case GCSsweep: { - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - if (*g->sweepgc == NULL) /* nothing more to sweep? */ - g->gcstate = GCSfinalize; /* end sweep phase */ - return GCSWEEPMAX*GCSWEEPCOST; + case GCSsweepudata: { + if (*g->sweepgc) { + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + return GCSWEEPMAX*GCSWEEPCOST; + } + else { + g->sweepgc = &g->allgc; /* go to next phase */ + g->gcstate = GCSsweep; + return GCSWEEPCOST; + } } - case GCSfinalize: { - if (g->tobefnz) { - GCTM(L, 1); - return GCFINALIZECOST; + case GCSsweep: { + if (*g->sweepgc) { + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + return GCSWEEPMAX*GCSWEEPCOST; } else { + /* sweep main thread */ + GCObject *mt = obj2gco(g->mainthread); + sweeplist(L, &mt, 1); checkSizes(L); - g->gcstate = GCSpause; /* end collection */ - return 0; + g->gcstate = GCSpause; /* finish collection */ + return GCSWEEPCOST; } } default: lua_assert(0); return 0; @@ -776,22 +914,6 @@ static l_mem singlestep (lua_State *L) { } -void luaC_step (lua_State *L) { - global_State *g = G(L); - l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ - lu_mem debt = g->totalbytes - g->GCthreshold; - lua_assert(g->gckind == KGC_NORMAL); - do { /* always perform at least one single step */ - lim -= singlestep(L); - } while (lim > 0 && g->gcstate != GCSpause); - g->GCthreshold = (g->gcstate != GCSpause) - ? g->totalbytes + GCSTEPSIZE - : (g->totalbytes/100) * g->gcpause; - /* compensate if GC is "behind schedule" (has some debt to pay) */ - if (g->GCthreshold > debt) g->GCthreshold -= debt; -} - - /* ** advances the garbage collector until it reaches a state allowed ** by 'statemask' @@ -803,29 +925,73 @@ void luaC_runtilstate (lua_State *L, int statesmask) { } +static void generationalcollection (lua_State *L) { + global_State *g = G(L); + if (g->lastmajormem == 0) { /* signal for another major collection? */ + luaC_fullgc(L, 0); /* perform a full regular collection */ + g->lastmajormem = g->totalbytes; /* update control */ + } + else { + luaC_runtilstate(L, bitmask(GCSpause)); /* run collection */ + if (g->totalbytes > g->lastmajormem/100 * g->gcpause) + g->lastmajormem = 0; /* signal for a major collection */ + } + g->GCdebt = stddebt(g); +} + + +static void step (lua_State *L) { + global_State *g = G(L); + l_mem lim = g->gcstepmul; /* how much to work */ + do { /* always perform at least one single step */ + lim -= singlestep(L); + } while (lim > 0 && g->gcstate != GCSpause); + if (g->gcstate != GCSpause) + g->GCdebt -= GCSTEPSIZE; + else + g->GCdebt = stddebt(g); +} + + +void luaC_step (lua_State *L) { + int i; + if (isgenerational(G(L))) generationalcollection(L); + else step(L); + for (i = 0; i < GCFINALIZENUM && G(L)->tobefnz; i++) + GCTM(L, 1); /* Call a few pending finalizers */ +} + + /* -** performs a full GC cycle; if "isememrgency", does not call +** performs a full GC cycle; if "isemergency", does not call ** finalizers (which could change stack positions) */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - lua_assert(g->gckind == KGC_NORMAL); - g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; - if (g->gcstate == GCSpropagate) { /* marking phase? */ + int origkind = g->gckind; + lua_assert(origkind != KGC_EMERGENCY); + if (!isemergency) /* do not run finalizers during emergency GC */ + callallpendingfinalizers(L, 1); + if (keepinvariant(g)) { /* marking phase? */ /* must sweep all objects to turn them back to white - (as white does not change, nothing will be collected) */ + (as white has not changed, nothing will be collected) */ g->sweepstrgc = 0; g->gcstate = GCSsweepstring; } - /* finish any pending sweep phase */ - luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); - markroot(L); /* start a new collection */ - /* run collector up to finalizers */ - luaC_runtilstate(L, bitmask(GCSfinalize)); - g->gckind = KGC_NORMAL; + g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL; + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + /* run entire collector */ + luaC_runtilstate(L, ~bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCSpause)); + if (origkind == KGC_GEN) { /* generational mode? */ + /* generational mode must always start in propagate phase */ + luaC_runtilstate(L, bitmask(GCSpropagate)); + } + g->gckind = origkind; + g->GCdebt = stddebt(g); if (!isemergency) /* do not run finalizers during emergency GC */ - luaC_runtilstate(L, ~bitmask(GCSfinalize)); - g->GCthreshold = (g->totalbytes/100) * g->gcpause; + callallpendingfinalizers(L, 1); } /* }====================================================== */ @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp $ +** $Id: lgc.h,v 2.41 2010/05/10 18:23:45 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -9,18 +9,51 @@ #include "lobject.h" +#include "lstate.h" + +/* +** Collectable objects may have one of three colors: white, which +** means the object is not marked; gray, which means the +** object is marked, but its references may be not marked; and +** black, which means that the object and all its references are marked. +** The main invariant of the garbage collector, while marking objects, +** is that a black object can never point to a white one. Moreover, +** any gray object must be in a "gray list" (gray, grayagain, weak, +** allweak, ephemeron) so that it can be visited again before finishing +** the collection cycle. These lists have no meaning when the invariant +** is not being enforced (e.g., sweep phase). +*/ /* ** Possible states of the Garbage Collector */ -#define GCSpause 0 -#define GCSpropagate 1 -#define GCSatomic 2 -#define GCSsweepstring 3 +#define GCSpropagate 0 +#define GCSatomic 1 +#define GCSsweepstring 2 +#define GCSsweepudata 3 #define GCSsweep 4 -#define GCSfinalize 5 +#define GCSpause 5 + + +#define issweepphase(g) \ + (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) + +#define isgenerational(g) ((g)->gckind == KGC_GEN) + +/* +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a non-generational collection, the sweep +** phase may brak the invariant, as objects turned white may point to +** still-black objects. The invariant is restored when sweep ends and +** all objects are white again. During a generational collection, the +** invariant must be kept all times. +*/ +#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) + +#define gcstopped(g) ((g)->GCdebt == MIN_LMEM) +#define stopgc(g) ((g)->GCdebt = MIN_LMEM) /* @@ -39,34 +72,33 @@ -/* -** 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 userdata: has been finalized -** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz -** bit 5 - object is fixed (should not be collected) -** bit 6 - object is "super" fixed (only the main thread) -*/ - +/* 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 /* for userdata: has been finalized */ +#define SEPARATED 4 /* " ": it's in 'udgc' list or in 'tobefnz' */ +#define FIXEDBIT 5 /* object is fixed (should not be collected) */ +#define OLDBIT 6 /* object is old (only in generational mode) */ +/* bit 7 is currently used by tests (luaL_checkmemory) */ -#define WHITE0BIT 0 -#define WHITE1BIT 1 -#define BLACKBIT 2 -#define FINALIZEDBIT 3 -#define SEPARATED 4 -#define FIXEDBIT 5 -#define SFIXEDBIT 6 #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) testbits((x)->gch.marked, WHITEBITS) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) -#define isgray(x) (!isblack(x) && !iswhite(x)) +#define isgray(x) /* neither white nor black */ \ + (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT))) + +#define isold(x) testbit((x)->gch.marked, OLDBIT) + +/* MOVE OLD rule: whenever an object is moved to the beginning of + a GC list, its old bit must be cleared */ +#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT) #define otherwhite(g) (g->currentwhite ^ WHITEBITS) -#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) +#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) #define changewhite(x) ((x)->gch.marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) @@ -76,8 +108,7 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_checkGC(L) \ - {condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);} +#define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);} #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ @@ -100,10 +131,10 @@ 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, GCObject **list, int offset); -LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); - +LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); +LUAI_FUNC void luaC_changemode (lua_State *L, int mode); #endif diff --git a/src/linit.c b/src/linit.c index a9430605..ff296cd7 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.23 2009/12/22 15:32:50 roberto Exp $ +** $Id: linit.c,v 1.24 2010/03/26 20:58:11 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ @@ -52,9 +52,9 @@ LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* call open functions from 'loadedlibs' */ for (lib = loadedlibs; lib->func; lib++) { - lua_pushcfunction(L, lib->func); + lua_settop(L, 0); lua_pushstring(L, lib->name); - lua_call(L, 1, 0); + (lib->func)(L); } /* add open functions from 'preloadedlibs' into 'package.preload' table */ lua_pushglobaltable(L); @@ -65,8 +65,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) { } lua_pop(L, 1); /* remove package.preload table */ #if defined(LUA_COMPAT_DEBUGLIB) - lua_pushglobaltable(L); - lua_getfield(L, -1, "require"); + lua_getglobal(L, "require"); lua_pushliteral(L, LUA_DBLIBNAME); lua_call(L, 1, 0); /* call 'require"debug"' */ lua_pop(L, 1); /* remove global table */ diff --git a/src/liolib.c b/src/liolib.c index 64fa43b4..c453cb95 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp $ +** $Id: liolib.c,v 2.88 2010/03/26 20:58:11 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -103,13 +103,12 @@ static FILE *tofile (lua_State *L) { } - /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ -static FILE **newfile (lua_State *L) { +static FILE **newprefile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ luaL_getmetatable(L, LUA_FILEHANDLE); @@ -118,6 +117,14 @@ static FILE **newfile (lua_State *L) { } +static FILE **newfile (lua_State *L) { + FILE **pf = newprefile(L); + lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */ + lua_setenv(L, -2); /* ... as environment for new file */ + return pf; +} + + /* ** function to (not) close the standard files stdin, stdout, and stderr */ @@ -156,7 +163,7 @@ static int io_fclose (lua_State *L) { static int aux_close (lua_State *L) { - lua_getfenv(L, 1); + lua_getenv(L, 1); lua_getfield(L, -1, "__close"); return (lua_tocfunction(L, -1))(L); } @@ -164,7 +171,7 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { if (lua_isnone(L, 1)) - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); tofile(L); /* make sure argument is a file */ return aux_close(L); } @@ -229,7 +236,7 @@ static int io_tmpfile (lua_State *L) { static FILE *getiofile (lua_State *L, int findex) { FILE *f; - lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + lua_rawgeti(L, lua_upvalueindex(1), findex); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) luaL_error(L, "standard %s file is closed", fnames[findex - 1]); @@ -250,10 +257,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_rawseti(L, LUA_ENVIRONINDEX, f); + lua_rawseti(L, lua_upvalueindex(1), f); } /* return current value */ - lua_rawgeti(L, LUA_ENVIRONINDEX, f); + lua_rawgeti(L, lua_upvalueindex(1), f); return 1; } @@ -271,35 +278,46 @@ static int io_output (lua_State *L) { static int io_readline (lua_State *L); -static void aux_lines (lua_State *L, int idx, int toclose) { - lua_pushvalue(L, idx); +static void aux_lines (lua_State *L, int toclose) { + int i; + int n = lua_gettop(L) - 1; /* number of arguments to read */ + /* ensure that arguments will fit here and into 'io_readline' stack */ + luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); + lua_pushvalue(L, 1); /* file handle */ + lua_pushinteger(L, n); /* number of arguments to read */ lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_pushcclosure(L, io_readline, 2); + for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */ + lua_pushcclosure(L, io_readline, 3 + n); } static int f_lines (lua_State *L) { tofile(L); /* check that it's a valid file handle */ - aux_lines(L, 1, 0); + aux_lines(L, 0); return 1; } static int io_lines (lua_State *L) { - if (lua_isnoneornil(L, 1)) { /* no arguments? */ - /* will iterate over default input */ - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); - return f_lines(L); + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ } - else { + else { /* open a new file */ const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); if (*pf == NULL) fileerror(L, 1, filename); - aux_lines(L, lua_gettop(L), 1); - return 1; + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ } + aux_lines(L, toclose); + return 1; } @@ -316,7 +334,10 @@ static int read_number (lua_State *L, FILE *f) { lua_pushnumber(L, d); return 1; } - else return 0; /* read fails */ + else { + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } } @@ -328,7 +349,7 @@ static int test_eof (lua_State *L, FILE *f) { } -static int read_line (lua_State *L, FILE *f) { +static int read_line (lua_State *L, FILE *f, int chop) { luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { @@ -342,7 +363,7 @@ static int read_line (lua_State *L, FILE *f) { if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { - luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ luaL_pushresult(&b); /* close buffer */ return 1; /* read at least an `eol' */ } @@ -375,7 +396,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int n; clearerr(f); if (nargs == 0) { /* no arguments? */ - success = read_line(L, f); + success = read_line(L, f, 1); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ @@ -394,7 +415,10 @@ static int g_read (lua_State *L, FILE *f, int first) { success = read_number(L, f); break; case 'l': /* line */ - success = read_line(L, f); + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); break; case 'a': /* file */ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ @@ -428,15 +452,22 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); - int success; + int i; + int n = lua_tointeger(L, lua_upvalueindex(2)); if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - success = read_line(L, f); - if (ferror(f)) - return luaL_error(L, "%s", strerror(errno)); - if (success) return 1; - else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + lua_settop(L , 1); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (!lua_isnil(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is nil: EOF or error */ + if (!lua_isnil(L, -1)) /* is there error information? */ + return luaL_error(L, "%s", lua_tostring(L, -1)); /* error */ + /* else EOF */ + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ @@ -552,23 +583,27 @@ static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, flib); /* file methods */ + luaL_register(L, NULL, flib); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ } static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { - *newfile(L) = f; + *newprefile(L) = f; if (k > 0) { - lua_pushvalue(L, -1); - lua_rawseti(L, LUA_ENVIRONINDEX, k); + lua_pushvalue(L, -1); /* copy new file */ + lua_rawseti(L, 1, k); /* add it to common upvalue */ } - lua_pushvalue(L, -2); /* copy environment */ - lua_setfenv(L, -2); /* set it */ - lua_setfield(L, -3, fname); + lua_pushvalue(L, 3); /* get environment for default files */ + lua_setenv(L, -2); /* set it as environment for file */ + lua_setfield(L, 2, fname); /* add file to module */ } -static void newfenv (lua_State *L, lua_CFunction cls) { +/* +** pushes a new table with {__close = cls} +*/ +static void newenv (lua_State *L, lua_CFunction cls) { lua_createtable(L, 0, 1); lua_pushcfunction(L, cls); lua_setfield(L, -2, "__close"); @@ -576,21 +611,21 @@ static void newfenv (lua_State *L, lua_CFunction cls) { LUAMOD_API int luaopen_io (lua_State *L) { + lua_settop(L, 0); createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ - newfenv(L, io_fclose); - lua_replace(L, LUA_ENVIRONINDEX); - /* open library */ - luaL_register(L, LUA_IOLIBNAME, iolib); + newenv(L, io_fclose); /* upvalue for all io functions at index 1 */ + lua_pushvalue(L, -1); /* copy to be consumed by 'openlib' */ + luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* new module at index 2 */ /* create (and set) default files */ - newfenv(L, io_noclose); /* close function for default files */ + newenv(L, io_noclose); /* environment for default files at index 3 */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, 0, "stderr"); lua_pop(L, 1); /* pop environment for default files */ - lua_getfield(L, -1, "popen"); - newfenv(L, io_pclose); /* create environment for 'popen' */ - lua_setfenv(L, -2); /* set fenv for 'popen' */ + lua_getfield(L, 2, "popen"); + newenv(L, io_pclose); /* create environment for 'popen' streams */ + lua_setupvalue(L, -2, 1); /* set it as upvalue for 'popen' */ lua_pop(L, 1); /* pop 'popen' */ return 1; } @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.34 2009/11/17 16:33:38 roberto Exp $ +** $Id: llex.c,v 2.37 2010/04/16 12:31:07 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -117,21 +117,30 @@ void luaX_syntaxerror (LexState *ls, const char *msg) { } +/* +** creates a new string and anchors it in function's table so that +** it will not be collected until the end of the function's compilation +** (by that time it should be anchored in function's prototype) +*/ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; TValue *o; /* entry for `str' */ - TString *ts = luaS_newlstr(L, str, l); - setsvalue2s(L, L->top++, ts); /* anchor string */ - o = luaH_setstr(L, ls->fs->h, ts); + TString *ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_setstr(L, ls->fs->h, ts); if (ttisnil(o)) { - setbvalue(o, 1); /* make sure `str' will not be collected */ + setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } - L->top--; + L->top--; /* remove string from stack */ return ts; } +/* +** increment line number and skips newline sequence (any of +** \n, \r, \n\r, or \r\n) +*/ static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); @@ -152,6 +161,8 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->linenumber = 1; ls->lastline = 1; ls->source = source; + ls->envn = luaS_new(L, "_ENV"); /* create env name */ + luaS_fix(ls->envn); /* never collect this name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ } @@ -174,6 +185,9 @@ static int check_next (LexState *ls, const char *set) { } +/* +** change all characters 'from' in buffer to 'to' +*/ static void buffreplace (LexState *ls, char from, char to) { size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); @@ -186,11 +200,14 @@ static void buffreplace (LexState *ls, char from, char to) { #define getlocaledecpoint() (localeconv()->decimal_point[0]) #endif +/* +** in case of format error, try to change decimal point separator to +** the one defined in the current locale and check again +*/ static void trydecpoint (LexState *ls, SemInfo *seminfo) { - /* format error: try to update decimal point separator */ char old = ls->decpoint; ls->decpoint = getlocaledecpoint(); - buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ + buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ @@ -216,6 +233,10 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { } +/* +** skip a sequence '[=*=[' or ']=*]' and return its number of '='s or +** -1 if sequence is malformed +*/ static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; @@ -246,8 +267,7 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } break; } - case '\n': - case '\r': { + case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ @@ -308,16 +328,16 @@ static int readdecesc (LexState *ls) { static void read_string (LexState *ls, int del, SemInfo *seminfo) { - save_and_next(ls); + save_and_next(ls); /* keep delimiter (for error messages) */ while (ls->current != del) { switch (ls->current) { case EOZ: lexerror(ls, "unfinished string", TK_EOS); - continue; /* to avoid warnings */ + break; /* to avoid warnings */ case '\n': case '\r': lexerror(ls, "unfinished string", TK_STRING); - continue; /* to avoid warnings */ + break; /* to avoid warnings */ case '\\': { /* escape sequences */ int c; /* final character to be saved */ next(ls); /* do not save the `\' */ @@ -333,6 +353,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { case '\n': case '\r': save(ls, '\n'); inclinenumber(ls); continue; case EOZ: continue; /* will raise an error next loop */ + case '*': { /* skip following span of spaces */ + next(ls); /* skip the '*' */ + while (lisspace(ls->current)) { + if (currIsNewline(ls)) inclinenumber(ls); + else next(ls); + } + continue; /* do not save 'c' */ + } default: { if (!lisdigit(ls->current)) c = ls->current; /* handles \\, \", \', and \? */ @@ -343,7 +371,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { } next(ls); save(ls, c); - continue; + break; } default: save_and_next(ls); @@ -359,31 +387,34 @@ static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { - case '\n': - case '\r': { + case '\n': case '\r': { /* line breaks */ inclinenumber(ls); - continue; + break; } - case '-': { + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '-': { /* '-' or '--' (comment) */ next(ls); if (ls->current != '-') return '-'; /* else is a comment */ next(ls); - if (ls->current == '[') { + if (ls->current == '[') { /* long comment? */ int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (sep >= 0) { - read_long_string(ls, NULL, sep); /* long comment */ - luaZ_resetbuffer(ls->buff); - continue; + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; } } /* else short comment */ while (!currIsNewline(ls) && ls->current != EOZ) - next(ls); - continue; + next(ls); /* skip until end of line (or end of file) */ + break; } - case '[': { + case '[': { /* long string or simply '[' */ int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); @@ -412,39 +443,30 @@ static int llex (LexState *ls, SemInfo *seminfo) { if (ls->current != '=') return '~'; else { next(ls); return TK_NE; } } - case '"': - case '\'': { + case '"': case '\'': { /* short literal strings */ read_string(ls, ls->current, seminfo); return TK_STRING; } - case '.': { + case '.': { /* '.', '..', '...', or number */ save_and_next(ls); if (check_next(ls, ".")) { if (check_next(ls, ".")) - return TK_DOTS; /* ... */ - else return TK_CONCAT; /* .. */ + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; - else { - read_numeral(ls, seminfo); - return TK_NUMBER; - } + /* else go through */ + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + read_numeral(ls, seminfo); + return TK_NUMBER; } case EOZ: { return TK_EOS; } default: { - if (lisspace(ls->current)) { - lua_assert(!currIsNewline(ls)); - next(ls); - continue; - } - else if (lisdigit(ls->current)) { - read_numeral(ls, seminfo); - return TK_NUMBER; - } - else if (lislalpha(ls->current)) { - /* identifier or reserved word */ + if (lislalpha(ls->current)) { /* identifier or reserved word? */ TString *ts; do { save_and_next(ls); @@ -458,10 +480,10 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_NAME; } } - else { + else { /* single-char tokens (+ - / ...) */ int c = ls->current; next(ls); - return c; /* single-char tokens (+ - / ...) */ + return c; } } } @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.62 2009/10/11 20:02:19 roberto Exp $ +** $Id: llex.h,v 1.65 2010/04/05 16:35:37 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -60,6 +60,7 @@ typedef struct LexState { Mbuffer *buff; /* buffer for tokens */ struct Varlist *varl; /* list of all active local variables */ TString *source; /* current source name */ + TString *envn; /* environment variable name */ char decpoint; /* locale decimal point */ } LexState; diff --git a/src/llimits.h b/src/llimits.h index 6bf49840..02be816e 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.77 2009/12/17 12:50:20 roberto Exp $ +** $Id: llimits.h,v 1.80 2010/05/07 18:44:12 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -30,6 +30,7 @@ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) +#define MIN_LMEM ((l_mem)~((~(lu_mem)0)>>1)) #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -59,7 +60,7 @@ typedef LUAI_UACNUMBER l_uacNumber; #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) #else -#define lua_assert(c) ((void)0) +#define lua_assert(c) /* empty */ #define check_exp(c,e) (e) #endif @@ -139,19 +140,19 @@ typedef lu_int32 Instruction; ** created/deleted/resumed/yielded. */ #if !defined(luai_userstateopen) -#define luai_userstateopen(L) ((void)L) +#define luai_userstateopen(L) ((void)L) #endif #if !defined(luai_userstateclose) -#define luai_userstateclose(L) ((void)L) +#define luai_userstateclose(L) ((void)L) #endif #if !defined(luai_userstatethread) -#define luai_userstatethread(L,L1) ((void)L) +#define luai_userstatethread(L,L1) ((void)L) #endif #if !defined(luai_userstatefree) -#define luai_userstatefree(L) ((void)L) +#define luai_userstatefree(L,L1) ((void)L) #endif #if !defined(luai_userstateresume) @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.74 2009/12/16 16:42:58 roberto Exp $ +** $Id: lmem.c,v 1.79 2010/05/05 18:49:56 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -79,13 +79,14 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) - if (nsize > realosize && g->GCthreshold != MAX_LUMEM) + if (nsize > realosize && !gcstopped(g)) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { - lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ - if (g->GCthreshold != MAX_LUMEM) { + api_check(L, nsize > realosize, + "realloc cannot fail when shrinking a block"); + if (!gcstopped(g)) { luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } @@ -94,6 +95,26 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { } lua_assert((nsize == 0) == (newblock == NULL)); g->totalbytes = (g->totalbytes - realosize) + nsize; + if (!gcstopped(g)) + g->GCdebt += nsize; /* give some credit to garbage collector */ +#if defined(TRACEMEM) + { /* auxiliary patch to monitor garbage collection. + ** To plot, gnuplot with following command: + ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines + */ + static unsigned long total = 0; /* our "time" */ + static FILE *f = NULL; /* output file */ + total++; /* "time" always grows */ + if ((total % 200) == 0) { + if (f == NULL) f = fopen(TRACEMEM, "w"); + fprintf(f, "%lu %u %d %d\n", total, + g->totalbytes, + gcstopped(g) ? 0 : g->GCdebt, + g->gcstate * 1000); + } + } +#endif + return newblock; } @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.35 2009/12/16 16:42:58 roberto Exp $ +** $Id: lmem.h,v 1.36 2010/04/08 17:16:46 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -13,8 +13,6 @@ #include "llimits.h" #include "lua.h" -#define MEMERRMSG "not enough memory" - #define luaM_reallocv(L,b,on,n,e) \ ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ diff --git a/src/loadlib.c b/src/loadlib.c index 90c785dc..793c658e 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.80 2010/01/13 16:30:27 roberto Exp $ +** $Id: loadlib.c,v 1.82 2010/03/19 15:02:34 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -353,9 +353,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function... */ - lua_pushglobaltable(L); /* ... and set the standard global table... */ - lua_setfenv(L, -2); /* ... as its environment */ + lua_pushcfunction(L, f); /* else create new function */ return 0; /* no errors */ } } @@ -435,7 +433,7 @@ static int ll_searchpath (lua_State *L) { static const char *findfile (lua_State *L, const char *name, const char *pname) { const char *path; - lua_getfield(L, LUA_ENVIRONINDEX, pname); + lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); @@ -509,7 +507,7 @@ static int loader_Croot (lua_State *L) { static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + lua_getfield(L, lua_upvalueindex(1), "preload"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); @@ -535,7 +533,7 @@ static int ll_require (lua_State *L) { return 1; /* package is already loaded */ } /* else must load it; iterate over available loaders */ - lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + lua_getfield(L, lua_upvalueindex(1), "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); lua_pushliteral(L, ""); /* error message accumulator */ @@ -579,14 +577,18 @@ static int ll_require (lua_State *L) { */ -static void setfenv (lua_State *L) { +/* +** FOR COMPATIBILITY ONLY: changes the _ENV variable of +** calling function +*/ +static void set_env (lua_State *L) { lua_Debug ar; if (lua_getstack(L, 1, &ar) == 0 || lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) luaL_error(L, LUA_QL("module") " not called from a Lua function"); lua_pushvalue(L, -2); /* copy new environment table to top */ - lua_setfenv(L, -2); + lua_setupvalue(L, -2, 1); lua_pop(L, 1); /* remove function */ } @@ -639,7 +641,7 @@ static int ll_module (lua_State *L) { modinit(L, modname); } lua_pushvalue(L, -1); - setfenv(L); + set_env(L); dooptions(L, loaded - 1); return 1; } @@ -709,12 +711,12 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); - lua_copy(L, -1, LUA_ENVIRONINDEX); /* create `loaders' table */ lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { - lua_pushcfunction(L, loaders[i]); + lua_pushvalue(L, -2); /* set 'package' as upvalue for all loaders */ + lua_pushcclosure(L, loaders[i], 1); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ @@ -731,8 +733,9 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_newtable(L); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); - luaL_register(L, NULL, ll_funcs); /* open lib into global table */ - lua_pop(L, 1); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_openlib(L, NULL, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ return 1; /* return 'package' table */ } diff --git a/src/lobject.c b/src/lobject.c index 8f5c5691..d4fff394 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.34 2009/11/26 11:39:20 roberto Exp $ +** $Id: lobject.c,v 2.40 2010/04/18 13:22:48 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -81,6 +81,10 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TSTRING: + return rawtsvalue(t1) == rawtsvalue(t2); + case LUA_TLCF: + return fvalue(t1) == fvalue(t2); default: lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); @@ -96,7 +100,7 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); case LUA_OPMOD: return luai_nummod(NULL, v1, v2); case LUA_OPPOW: return luai_numpow(NULL, v1, v2); - case LUA_OPUNM: return luai_numunm(N, v1); + case LUA_OPUNM: return luai_numunm(NULL, v1); default: lua_assert(0); return 0; } } @@ -108,24 +112,21 @@ int luaO_str2d (const char *s, lua_Number *result) { if (endptr == s) return 0; /* conversion failed */ if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ *result = cast_num(strtoul(s, &endptr, 16)); - if (*endptr == '\0') return 1; /* most common case */ while (lisspace(cast(unsigned char, *endptr))) endptr++; - if (*endptr != '\0') return 0; /* invalid trailing characters? */ - return 1; + return (*endptr == '\0'); /* OK if no trailing characters */ } -static void pushstr (lua_State *L, const char *str) { - setsvalue2s(L, L->top, luaS_new(L, str)); +static void pushstr (lua_State *L, const char *str, size_t l) { + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); incr_top(L); } /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - int n = 1; - pushstr(L, ""); + int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; @@ -135,14 +136,13 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; - pushstr(L, s); + pushstr(L, s, strlen(s)); break; } case 'c': { - char buff[2]; - buff[0] = cast(char, va_arg(argp, int)); - buff[1] = '\0'; - pushstr(L, buff); + char buff; + buff = cast(char, va_arg(argp, int)); + pushstr(L, &buff, 1); break; } case 'd': { @@ -157,12 +157,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ - sprintf(buff, "%p", va_arg(argp, void *)); - pushstr(L, buff); + int l = sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff, l); break; } case '%': { - pushstr(L, "%"); + pushstr(L, "%", 1); break; } default: { @@ -175,8 +175,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { n += 2; fmt = e+2; } - pushstr(L, fmt); - luaV_concat(L, n+1); + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); } diff --git a/src/lobject.h b/src/lobject.h index 2969fe7d..73634220 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.34 2010/01/08 20:00:20 roberto Exp $ +** $Id: lobject.h,v 2.40 2010/05/07 18:44:46 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -16,21 +16,21 @@ #include "lua.h" -/* tags for values visible from Lua */ -#define LAST_TAG LUA_TTHREAD - -#define NUM_TAGS (LAST_TAG+1) - - /* ** Extra tags for non-values */ -#define LUA_TPROTO (LAST_TAG+1) -#define LUA_TUPVAL (LAST_TAG+2) -#define LUA_TDEADKEY (LAST_TAG+3) +#define LUA_TPROTO LUA_NUMTAGS +#define LUA_TUPVAL (LUA_NUMTAGS+1) +#define LUA_TDEADKEY (LUA_NUMTAGS+2) /* +** Variant tag for light C functions (negative to be considered +** non collectable by 'iscollectable') +*/ +#define LUA_TLCF (~0x0F | LUA_TFUNCTION) + +/* ** Union of all collectable objects */ typedef union GCObject GCObject; @@ -60,6 +60,7 @@ typedef union { void *p; lua_Number n; int b; + lua_CFunction f; } Value; @@ -79,12 +80,26 @@ typedef struct lua_TValue { #define NILCONSTANT {NULL}, LUA_TNIL +/* +** type tag of a TValue +*/ +#define ttype(o) ((o)->tt_) + + +/* +** type tag of a TValue with no variants +*/ +#define ttypenv(o) (ttype(o) & 0x0F) + + /* Macros to test type */ #define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER) #define ttisstring(o) (ttype(o) == LUA_TSTRING) #define ttistable(o) (ttype(o) == LUA_TTABLE) -#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) +#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION) +#define ttisclosure(o) (ttype(o) == LUA_TFUNCTION) +#define ttislcf(o) (ttype(o) == LUA_TLCF) #define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) #define ttisthread(o) (ttype(o) == LUA_TTHREAD) @@ -92,7 +107,6 @@ typedef struct lua_TValue { #define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY) /* Macros to access values */ -#define ttype(o) ((o)->tt_) #define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc) #define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p) #define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n) @@ -100,16 +114,15 @@ typedef struct lua_TValue { #define tsvalue(o) (&rawtsvalue(o)->tsv) #define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value_.gc->u) #define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisfunction(o), &(o)->value_.gc->cl) +#define clvalue(o) check_exp(ttisclosure(o), &(o)->value_.gc->cl) +#define fvalue(o) check_exp(ttislcf(o), (o)->value_.f) #define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b) #define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) -/* -** for internal debug only -*/ + #define iscollectable(o) (ttype(o) >= LUA_TSTRING) #define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) @@ -126,8 +139,10 @@ typedef struct lua_TValue { #define setnvalue(obj,x) \ { TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; } -#define changenvalue(obj,x) \ - ( lua_assert((obj)->tt_==LUA_TNUMBER), (obj)->value_.n=(x) ) +#define setfvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value_.f=(x); i_o->tt_=LUA_TLCF; } + +#define changenvalue(o,x) check_exp((o)->tt_==LUA_TNUMBER, (o)->value_.n=(x)) #define setpvalue(obj,x) \ { TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; } @@ -264,7 +279,6 @@ typedef struct Proto { lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; - lu_byte envreg; /* register in outer function with initial environment */ } Proto; @@ -298,8 +312,7 @@ typedef struct UpVal { */ #define ClosureHeader \ - CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ - struct Table *env + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist typedef struct CClosure { ClosureHeader; @@ -321,8 +334,7 @@ typedef union Closure { } Closure; -#define iscfunction(o) (ttisfunction(o) && clvalue(o)->c.isC) -#define isLfunction(o) (ttisfunction(o) && !clvalue(o)->c.isC) +#define isLfunction(o) (ttisclosure(o) && !clvalue(o)->c.isC) #define getproto(o) (clvalue(o)->l.p) diff --git a/src/lopcodes.c b/src/lopcodes.c index 188c7a55..cc1acb13 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.41 2009/11/19 19:06:52 roberto Exp $ +** $Id: lopcodes.c,v 1.43 2010/03/12 19:14:06 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -19,9 +19,9 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "LOADBOOL", "LOADNIL", "GETUPVAL", - "GETGLOBAL", + "GETTABUP", "GETTABLE", - "SETGLOBAL", + "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", @@ -67,9 +67,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ - ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ + ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ diff --git a/src/lopcodes.h b/src/lopcodes.h index 19ddfea3..4140db3a 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.133 2009/11/19 19:06:52 roberto Exp $ +** $Id: lopcodes.h,v 1.135 2010/03/12 19:14:06 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -171,10 +171,10 @@ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ OP_GETUPVAL,/* A B R(A) := UpValue[B] */ -OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx - 1)] */ +OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */ OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ -OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx - 1)] := R(A) */ +OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */ OP_SETUPVAL,/* A B UpValue[B] := R(A) */ OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ @@ -243,8 +243,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). - (*) In OP_LOADK, OP_GETGLOBAL, and OP_SETGLOBAL, if (Bx == 0) then next - 'instruction' is EXTRAARG(real Bx). + (*) In OP_LOADK, if (Bx == 0) then next 'instruction' is EXTRAARG(real Bx). (*) For comparisons, A specifies what condition the test should accept (true or false). diff --git a/src/lparser.c b/src/lparser.c index cc21f67f..762cb4fc 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp $ +** $Id: lparser.c,v 2.86 2010/05/15 13:32:02 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -74,9 +74,10 @@ static void error_expected (LexState *ls, int token) { static void errorlimit (FuncState *fs, int limit, const char *what) { const char *msg; - const char *where = (fs->f->linedefined == 0) ? - "main function" : - luaO_pushfstring(fs->L, "function at line %d", fs->f->linedefined); + int line = fs->f->linedefined; + const char *where = (line == 0) + ? "main function" + : luaO_pushfstring(fs->L, "function at line %d", line); msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s", what, limit, where); luaX_syntaxerror(fs->ls, msg); @@ -207,27 +208,27 @@ static void removevars (FuncState *fs, int tolevel) { } -static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { +static int searchupvalue (FuncState *fs, TString *name) { int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; - int instk = (v->k == VLOCAL); - lua_assert(instk || v->k == VUPVAL); - for (i=0; i<fs->nups; i++) { - if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) { - lua_assert(f->upvalues[i].name == name); - return i; - } - } - /* new one */ checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, UCHAR_MAX, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].instack = (v->k == VLOCAL); + f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->L, f, name); - f->upvalues[fs->nups].instack = cast_byte(instk); - f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); return fs->nups++; } @@ -235,13 +236,17 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { static int searchvar (FuncState *fs, TString *n) { int i; for (i=fs->nactvar-1; i >= 0; i--) { - if (n == getlocvar(fs, i)->varname) + if (eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ } +/* + Mark block where variable at given level was defined + (to emit OP_CLOSE later). +*/ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl && bl->nactvar > level) bl = bl->previous; @@ -249,22 +254,30 @@ static void markupval (FuncState *fs, int level) { } +/* + Find variable with given name 'n'. If it is an upvalue, add this + upvalue into all intermediate functions. +*/ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ - return VGLOBAL; /* default is global variable */ + return VVOID; /* default is global */ else { - int v = searchvar(fs, n); /* look up at current level */ - if (v >= 0) { - init_exp(var, VLOCAL, v); + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) { /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } - else { /* not found at current level; try upper one */ - if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) - return VGLOBAL; - var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ - var->k = VUPVAL; /* upvalue in this level */ + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ + return VVOID; /* not found; is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); return VUPVAL; } } @@ -274,15 +287,12 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VGLOBAL) { - if (fs->envreg == NO_REG) /* regular global? */ - init_exp(var, VGLOBAL, luaK_stringK(fs, varname)); - else { /* "globals" are in current lexical environment */ - expdesc key; - init_exp(var, VLOCAL, fs->envreg); /* current environment */ - codestring(ls, &key, varname); /* key is variable name */ - luaK_indexed(fs, var, &key); /* env[varname] */ - } + if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get _ENV variable */ + lua_assert(var->k == VLOCAL || var->k == VUPVAL); + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ } } @@ -351,7 +361,6 @@ static void pushclosure (LexState *ls, Proto *clp, expdesc *v) { while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = clp; /* initial environment for new function is current lexical environment */ - clp->envreg = fs->envreg; luaC_objbarrier(ls->L, f, clp); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); } @@ -374,7 +383,6 @@ static void open_func (LexState *ls, FuncState *fs) { fs->nlocvars = 0; fs->nactvar = 0; fs->firstlocal = ls->varl->nactvar; - fs->envreg = NO_REG; fs->bl = NULL; f = luaF_newproto(L); fs->f = f; @@ -418,26 +426,36 @@ static void close_func (LexState *ls) { } +/* +** opens the main function, which is a regular vararg function with an +** upvalue named '_ENV' +*/ +static void open_mainfunc (LexState *ls, FuncState *fs) { + expdesc v; + open_func(ls, fs); + fs->f->is_vararg = 1; /* main function is always vararg */ + init_exp(&v, VLOCAL, 0); + newupvalue(fs, ls->envn, &v); /* create '_ENV' upvalue */ +} + + Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, const char *name) { - struct LexState lexstate; - struct FuncState funcstate; + LexState lexstate; + FuncState funcstate; TString *tname = luaS_new(L, name); setsvalue2s(L, L->top, tname); /* push name to protect it */ incr_top(L); lexstate.buff = buff; lexstate.varl = varl; luaX_setinput(L, &lexstate, z, tname); - open_func(&lexstate, &funcstate); - funcstate.f->is_vararg = 1; /* main function is always vararg */ + open_mainfunc(&lexstate, &funcstate); luaX_next(&lexstate); /* read first token */ - chunk(&lexstate); + chunk(&lexstate); /* read main chunk */ check(&lexstate, TK_EOS); close_func(&lexstate); L->top--; /* pop name */ - lua_assert(funcstate.prev == NULL); - lua_assert(funcstate.nups == 0); - lua_assert(lexstate.fs == NULL); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); return funcstate.f; } @@ -452,7 +470,7 @@ static void fieldsel (LexState *ls, expdesc *v) { /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; - luaK_exp2anyreg(fs, v); + luaK_exp2anyregup(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); @@ -653,15 +671,12 @@ static int explist1 (LexState *ls, expdesc *v) { } -static void funcargs (LexState *ls, expdesc *f) { +static void funcargs (LexState *ls, expdesc *f, int line) { FuncState *fs = ls->fs; expdesc args; int base, nparams; - int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ - if (line != ls->lastline) - luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; @@ -738,6 +753,7 @@ static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; + int line = ls->linenumber; prefixexp(ls, v); for (;;) { switch (ls->t.token) { @@ -747,7 +763,7 @@ static void primaryexp (LexState *ls, expdesc *v) { } case '[': { /* `[' exp1 `]' */ expdesc key; - luaK_exp2anyreg(fs, v); + luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; @@ -757,12 +773,12 @@ static void primaryexp (LexState *ls, expdesc *v) { luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); - funcargs(ls, v); + funcargs(ls, v, line); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); - funcargs(ls, v); + funcargs(ls, v, line); break; } default: return; @@ -877,9 +893,10 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { + int line = ls->linenumber; luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls->fs, uop, v); + luaK_prefix(ls->fs, uop, v, line); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ @@ -887,11 +904,12 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; + int line = ls->linenumber; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); - luaK_posfix(ls->fs, op, v, &v2); + luaK_posfix(ls->fs, op, v, &v2, line); op = nextop; } leavelevel(ls); @@ -951,24 +969,27 @@ struct LHS_assign { ** local value in a safe place and use this safe copy in the previous ** assignment. */ -static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v, + expkind ix, OpCode op) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { - if (lh->v.k == VINDEXED) { + if (lh->v.k == ix) { if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ conflict = 1; + lh->v.k = VINDEXED; lh->v.u.s.info = extra; /* previous assignment will use safe copy */ } - if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ + if (v->k == VLOCAL && lh->v.u.s.aux == v->u.s.info) { /* conflict? */ conflict = 1; + lua_assert(lh->v.k == VINDEXED); lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict) { - luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ + luaK_codeABC(fs, op, fs->freereg, v->u.s.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } @@ -976,14 +997,16 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; - check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, + check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXEDUP, "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) - check_conflict(ls, lh, &nv.v); + check_conflict(ls, lh, &nv.v, VINDEXED, OP_MOVE); + else if (nv.v.k == VUPVAL) + check_conflict(ls, lh, &nv.v, VINDEXEDUP, OP_GETUPVAL); checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, "variable names"); assignment(ls, &nv, nvars+1); @@ -1274,24 +1297,6 @@ static void funcstat (LexState *ls, int line) { } -static void instat (LexState *ls, int line) { - /* instat -> IN exp DO block END */ - FuncState *fs = ls->fs; - int oldenv = fs->envreg; /* save current environment */ - BlockCnt bl; - luaX_next(ls); /* skip IN */ - enterblock(fs, &bl, 0); /* scope for environment variable */ - new_localvarliteral(ls, "(environment)"); - fs->envreg = exp1(ls); /* new environment */ - adjustlocalvars(ls, 1); - checknext(ls, TK_DO); - block(ls); - leaveblock(fs); - check_match(ls, TK_END, TK_IN, line); - fs->envreg = oldenv; /* restore outer environment */ -} - - static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; @@ -1311,7 +1316,6 @@ static void retstat (LexState *ls) { FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ - luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { @@ -1342,6 +1346,10 @@ static void retstat (LexState *ls) { static int statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + return 0; + } case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); return 0; @@ -1356,10 +1364,6 @@ static int statement (LexState *ls) { check_match(ls, TK_END, TK_DO, line); return 0; } - case TK_IN: { - instat(ls, line); - return 0; - } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); return 0; @@ -1368,8 +1372,8 @@ static int statement (LexState *ls) { repeatstat(ls, line); return 0; } - case TK_FUNCTION: { - funcstat(ls, line); /* stat -> funcstat */ + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); return 0; } case TK_LOCAL: { /* stat -> localstat */ @@ -1381,6 +1385,7 @@ static int statement (LexState *ls) { return 0; } case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ retstat(ls); return 1; /* must be last statement */ } @@ -1389,9 +1394,9 @@ static int statement (LexState *ls) { breakstat(ls); return 1; /* must be last statement */ } - default: { + default: { /* stat -> func | assignment */ exprstat(ls); - return 0; /* to avoid warnings */ + return 0; } } } @@ -1403,7 +1408,8 @@ static void chunk (LexState *ls) { enterlevel(ls); while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); - testnext(ls, ';'); + if (islast) + testnext(ls, ';'); lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ diff --git a/src/lparser.h b/src/lparser.h index 2ad0a509..9e406a7b 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.61 2009/10/11 20:02:19 roberto Exp $ +** $Id: lparser.h,v 1.63 2010/03/12 19:14:06 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,10 +23,10 @@ typedef enum { VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ - VLOCAL, /* info = local register; aux = read only */ - VUPVAL, /* info = index of upvalue in 'upvalues'; aux = read only */ - VGLOBAL, /* info = index of table; aux = index of global name in `k' */ - VINDEXED, /* info = table register; aux = index register (or `k') */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in 'upvalues' */ + VINDEXED, /* info = table R/K; aux = index R/K */ + VINDEXEDUP, /* info = table upvalue; aux = R/K */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VNONRELOC, /* info = result register */ @@ -80,7 +80,6 @@ typedef struct FuncState { short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ lu_byte nups; /* number of upvalues */ - lu_byte envreg; /* register holding current lexical environment */ } FuncState; diff --git a/src/lstate.c b/src/lstate.c index 426fdec6..6ea00b62 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.68 2009/12/22 15:32:50 roberto Exp $ +** $Id: lstate.c,v 2.85 2010/04/30 18:36:22 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -26,7 +26,7 @@ #if !defined(LUAI_GCPAUSE) -#define LUAI_GCPAUSE 162 /* 162% (wait memory to double before next GC) */ +#define LUAI_GCPAUSE 200 /* 200% */ #endif #if !defined(LUAI_GCMUL) @@ -34,6 +34,9 @@ #endif +#define MEMERRMSG "not enough memory" + + /* ** thread state + extra space */ @@ -87,7 +90,7 @@ void luaE_freeCI (lua_State *L) { static void stack_init (lua_State *L1, lua_State *L) { - int i; + int i; CallInfo *ci; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); L1->stacksize = BASIC_STACK_SIZE; @@ -96,32 +99,22 @@ static void stack_init (lua_State *L1, lua_State *L) { L1->top = L1->stack; L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; /* initialize first ci */ - L1->ci->func = L1->top; + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ - L1->ci->top = L1->top + LUA_MINSTACK; - L1->ci->callstatus = 0; + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; } static void freestack (lua_State *L) { - L->ci = &L->base_ci; /* reset 'ci' list */ + if (L->stack == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ luaE_freeCI(L); - luaM_freearray(L, L->stack, L->stacksize); -} - - -/* -** Calls the function in variable pointed to by userdata in first argument -** (Userdata cannot point directly to the function because pointer to -** function is not compatible with void*.) -*/ -static int cpcall (lua_State *L) { - lua_CFunction f = *(lua_CFunction *)lua_touserdata(L, 1); - lua_remove(L, 1); /* remove f from stack */ - /* restore original environment for 'cpcall' */ - lua_pushglobaltable(L); - lua_replace(L, LUA_ENVIRONINDEX); - return f(L); + luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } @@ -129,7 +122,6 @@ static int cpcall (lua_State *L) { ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { - Closure *cp; TValue mt; /* create registry */ Table *registry = luaH_new(L); @@ -138,13 +130,8 @@ static void init_registry (lua_State *L, global_State *g) { /* registry[LUA_RIDX_MAINTHREAD] = L */ setthvalue(L, &mt, L); setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt); - /* registry[LUA_RIDX_CPCALL] = cpcall */ - cp = luaF_newCclosure(L, 0, g->l_gt); - cp->c.f = cpcall; - setclvalue(L, &mt, cp); - setobj2t(L, luaH_setint(L, registry, LUA_RIDX_CPCALL), &mt); - /* registry[LUA_RIDX_GLOBALS] = l_gt */ - sethvalue(L, &mt, g->l_gt); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &mt, luaH_new(L)); setobj2t(L, luaH_setint(L, registry, LUA_RIDX_GLOBALS), &mt); } @@ -156,13 +143,14 @@ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ - g->l_gt = luaH_new(L); /* table of globals */ init_registry(L, g); luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); - luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g->GCthreshold = 4*g->totalbytes; + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaS_fix(g->memerrmsg); /* it should never be collected */ + g->GCdebt = 0; } @@ -173,6 +161,7 @@ static void f_luaopen (lua_State *L, void *ud) { static void preinit_state (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; + L->ci = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; @@ -183,8 +172,6 @@ static void preinit_state (lua_State *L, global_State *g) { L->openupval = NULL; L->nny = 1; L->status = LUA_OK; - L->base_ci.next = L->base_ci.previous = NULL; - L->ci = &L->base_ci; L->errfunc = 0; } @@ -209,14 +196,13 @@ LUA_API lua_State *lua_newthread (lua_State *L) { setthvalue(L, L->top, L1); api_incr_top(L); preinit_state(L1, G(L)); - stack_init(L1, L); /* init stack */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); - lua_assert(iswhite(obj2gco(L1))); - lua_unlock(L); luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); return L1; } @@ -225,7 +211,7 @@ void luaE_freethread (lua_State *L, lua_State *L1) { LX *l = fromstate(L1); luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); - luai_userstatefree(L1); + luai_userstatefree(L, L1); freestack(L1); luaM_free(L, l); } @@ -235,7 +221,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; - LG *l = cast(LG *, (*f)(ud, NULL, 0, sizeof(LG))); + LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); if (l == NULL) return NULL; L = &l->l.l; g = &l->g; @@ -245,29 +231,31 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { L->marked = luaC_white(g); g->gckind = KGC_NORMAL; g->nCcalls = 0; - set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; - g->GCthreshold = MAX_LUMEM; /* no GC while building state */ + stopgc(g); /* no GC while building state */ + g->lastmajormem = 0; g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); - g->l_gt = NULL; luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->version = lua_version(NULL); g->gcstate = GCSpause; - g->rootgc = obj2gco(L); + g->allgc = NULL; + g->udgc = NULL; g->tobefnz = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; - for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; + for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { /* memory allocation error: free partial state */ close_state(L); diff --git a/src/lstate.h b/src/lstate.h index 4ca3e02f..e829ed4a 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.52 2009/12/22 15:32:50 roberto Exp $ +** $Id: lstate.h,v 2.65 2010/05/03 17:39:48 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -19,7 +19,7 @@ ** Some notes about garbage-collected objects: All objects in Lua must ** be kept somehow accessible until being freed. ** -** Lua keeps most objects linked in list g->rootgc. The link uses field +** Lua keeps most objects linked in list g->allgc. The link uses field ** 'next' of the CommonHeader. ** ** Strings are kept in several lists headed by the array g->strt.hash. @@ -32,9 +32,7 @@ ** when traversing the respective threads, but the thread may already be ** dead, while the upvalue is still accessible through closures.) ** -** Userdata with finalizers are kept in the list g->rootgc, but after -** the mainthread, which should be otherwise the last element in the -** list, as it was the first one inserted there. +** Userdata with finalizers are kept in the list g->udgc. ** ** The list g->tobefnz links all userdata being finalized. @@ -56,8 +54,8 @@ struct lua_longjmp; /* defined in ldo.c */ /* kinds of Garbage Collection */ #define KGC_NORMAL 0 -#define KGC_FORCED 1 /* gc was forced by the program */ -#define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */ +#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ +#define KGC_GEN 2 /* generational collection */ typedef struct stringtable { @@ -85,7 +83,7 @@ typedef struct CallInfo { int ctx; /* context info. in case of yields */ lua_CFunction k; /* continuation in case of yields */ ptrdiff_t old_errfunc; - ptrdiff_t oldtop; + ptrdiff_t extra; lu_byte old_allowhook; lu_byte status; } c; @@ -106,7 +104,6 @@ typedef struct CallInfo { #define CIST_TAIL (1<<6) /* call was tail called */ -#define curr_func(L) (clvalue(L->ci->func)) #define ci_func(ci) (clvalue((ci)->func)) #define isLua(ci) ((ci)->callstatus & CIST_LUA) @@ -115,15 +112,20 @@ typedef struct CallInfo { ** `global state', shared by all threads of this state */ typedef struct global_State { - stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ + lu_mem totalbytes; /* number of bytes currently allocated */ + l_mem GCdebt; /* when positive, run a GC step */ + lu_mem lastmajormem; /* memory in use after last major collection */ + stringtable strt; /* hash table for strings */ + TValue l_registry; unsigned short nCcalls; /* number of nested C calls */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ int sweepstrgc; /* position of sweep in `strt' */ - GCObject *rootgc; /* list of all collectable objects */ + GCObject *allgc; /* list of all collectable objects */ + GCObject *udgc; /* list of collectable userdata with finalizers */ GCObject **sweepgc; /* current position of sweep */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ @@ -131,19 +133,16 @@ typedef struct global_State { GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ + UpVal uvhead; /* head of double-linked list of all open upvalues */ Mbuffer buff; /* temporary buffer for string concatenation */ - lu_mem GCthreshold; /* when totalbytes > GCthreshold, run GC step */ - lu_mem totalbytes; /* number of bytes currently allocated */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ - TValue l_registry; - struct Table *l_gt; /* table of globals */ struct lua_State *mainthread; - UpVal uvhead; /* head of double-linked list of all open upvalues */ const lua_Number *version; /* pointer to version number */ - struct Table *mt[NUM_TAGS]; /* metatables for basic types */ + TString *memerrmsg; /* memory-error message */ TString *tmname[TM_N]; /* array with tag-method names */ + struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ } global_State; @@ -166,7 +165,6 @@ struct lua_State { int basehookcount; int hookcount; lua_Hook hook; - TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ diff --git a/src/lstring.c b/src/lstring.c index 69b96d02..145621b6 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.16 2009/12/16 16:42:58 roberto Exp $ +** $Id: lstring.c,v 2.18 2010/05/10 18:23:45 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -37,6 +37,7 @@ void luaS_resize (lua_State *L, int newsize) { unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ gch(p)->next = tb->hash[h]; /* chain it */ tb->hash[h] = p; + resetoldbit(p); /* see MOVE OLD rule */ p = next; } } @@ -94,6 +95,11 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { } +TString *luaS_new (lua_State *L, const char *str) { + return luaS_newlstr(L, str, strlen(str)); +} + + Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) diff --git a/src/lstring.h b/src/lstring.h index 1d2e91ea..d708a1b0 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ +** $Id: lstring.h,v 1.46 2010/04/05 16:26:37 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -7,7 +7,6 @@ #ifndef lstring_h #define lstring_h - #include "lgc.h" #include "lobject.h" #include "lstate.h" @@ -17,15 +16,22 @@ #define sizeudata(u) (sizeof(union Udata)+(u)->len) -#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + +/* +** as all string are internalized, string equality becomes +** pointer equality +*/ +#define eqstr(a,b) ((a) == (b)) + LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); #endif diff --git a/src/lstrlib.c b/src/lstrlib.c index 0c03b493..a5c3a204 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.148 2010/01/04 16:37:19 roberto Exp $ +** $Id: lstrlib.c,v 1.152 2010/05/04 17:20:33 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -65,12 +65,13 @@ static int str_sub (lua_State *L) { static int str_reverse (lua_State *L) { - size_t l; + size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); - while (l--) luaL_addchar(&b, s[l]); - luaL_pushresult(&b); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); return 1; } @@ -80,10 +81,10 @@ static int str_lower (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) - luaL_addchar(&b, tolower(uchar(s[i]))); - luaL_pushresult(&b); + p[i] = tolower(uchar(s[i])); + luaL_pushresultsize(&b, l); return 1; } @@ -93,10 +94,10 @@ static int str_upper (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) - luaL_addchar(&b, toupper(uchar(s[i]))); - luaL_pushresult(&b); + p[i] = toupper(uchar(s[i])); + luaL_pushresultsize(&b, l); return 1; } @@ -136,13 +137,13 @@ static int str_char (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; luaL_Buffer b; - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, n); for (i=1; i<=n; i++) { int c = luaL_checkint(L, i); luaL_argcheck(L, uchar(c) == c, i, "invalid value"); - luaL_addchar(&b, uchar(c)); + p[i - 1] = uchar(c); } - luaL_pushresult(&b); + luaL_pushresultsize(&b, n); return 1; } @@ -179,7 +180,8 @@ static int str_dump (lua_State *L) { typedef struct MatchState { const char *src_init; /* init of source string */ - const char *src_end; /* end (`\0') of source string */ + const char *src_end; /* end ('\0') of source string */ + const char *p_end; /* end ('\0') of pattern */ lua_State *L; int level; /* total number of captures (finished or unfinished) */ struct { @@ -212,16 +214,16 @@ static int capture_to_close (MatchState *ms) { static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { - if (*p == '\0') + if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ - if (*p == '\0') + if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); - if (*(p++) == L_ESC && *p != '\0') + if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; @@ -245,7 +247,7 @@ static int match_class (int c, int cl) { case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; + case 'z' : res = (c == 0); break; /* deprecated option */ default: return (cl == c); } return (islower(cl) ? res : !res); @@ -290,8 +292,9 @@ static const char *match (MatchState *ms, const char *s, const char *p); static const char *matchbalance (MatchState *ms, const char *s, const char *p) { - if (*p == 0 || *(p+1) == 0) - luaL_error(ms->L, "unbalanced pattern"); + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern " + "(missing arguments to " LUA_QL("%%b") ")"); if (*s != *p) return NULL; else { int b = *p; @@ -374,6 +377,8 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ + if (p == ms->p_end) /* end of pattern? */ + return s; /* match succeeded */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ @@ -384,11 +389,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case '\0': { /* end of pattern */ - return s; /* match succeeded */ - } case '$': { - if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */ return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; } @@ -418,12 +420,12 @@ static const char *match (MatchState *ms, const char *s, const char *p) { if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } - default: break; /* go through to 'dflt' */ + default: goto dflt; } } default: dflt: { /* pattern class plus optional sufix */ const char *ep = classend(ms, p); /* points to what is next */ - int m = s<ms->src_end && singlematch(uchar(*s), p, ep); + int m = s < ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; @@ -503,32 +505,36 @@ static int push_captures (MatchState *ms, const char *s, const char *e) { static int str_find_aux (lua_State *L, int find) { - size_t l1, l2; - const char *s = luaL_checklstring(L, 1, &l1); - const char *p = luaL_checklstring(L, 2, &l2); - size_t init = posrelat(luaL_optinteger(L, 3, 1), l1); + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; - else if (init > l1 + 1) { /* start after string's end? */ + else if (init > ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } if (find && (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, l1 - init + 1, p, l2); + const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp); if (s2) { lua_pushinteger(L, s2 - s + 1); - lua_pushinteger(L, s2 - s + l2); + lua_pushinteger(L, s2 - s + lp); return 2; } } else { MatchState ms; - int anchor = (*p == '^') ? (p++, 1) : 0; const char *s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } ms.L = L; ms.src_init = s; - ms.src_end = s + l1; + ms.src_end = s + ls; + ms.p_end = p + lp; do { const char *res; ms.level = 0; @@ -560,13 +566,14 @@ static int str_match (lua_State *L) { static int gmatch_aux (lua_State *L) { MatchState ms; - size_t ls; + size_t ls, lp; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - const char *p = lua_tostring(L, lua_upvalueindex(2)); + const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; + ms.p_end = p + lp; for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { @@ -658,12 +665,12 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, static int str_gsub (lua_State *L) { - size_t srcl; + size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checkstring(L, 2); + const char *p = luaL_checklstring(L, 2, &lp); int tr = lua_type(L, 3); size_t max_s = luaL_optinteger(L, 4, srcl+1); - int anchor = (*p == '^') ? (p++, 1) : 0; + int anchor = (*p == '^'); size_t n = 0; MatchState ms; luaL_Buffer b; @@ -671,9 +678,13 @@ static int str_gsub (lua_State *L) { tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, "string/function/table expected"); luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } ms.L = L; ms.src_init = src; ms.src_end = src+srcl; + ms.p_end = p + lp; while (n < max_s) { const char *e; ms.level = 0; @@ -698,11 +709,18 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ + /* -** length modifier for integer conversions ** in 'string.format' and -** integer type corresponding to the previous length +** {====================================================== +** STRING FORMAT +** ======================================================= */ +/* +** LUA_INTFRMLEN is the length modifier for integer conversions in +** 'string.format'; LUA_INTFRM_T is the integer type corresponding to +** the previous length +*/ #if defined(LUA_USELONGLONG) #define LUA_INTFRMLEN "ll" @@ -738,7 +756,7 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { } else if (*s == '\0' || iscntrl(uchar(*s))) { char buff[10]; - if (*s != '\0' && !isdigit(uchar(*(s+1)))) + if (!isdigit(uchar(*(s+1)))) sprintf(buff, "\\%d", uchar(*s)); else sprintf(buff, "\\%03d", uchar(*s)); @@ -773,6 +791,9 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { } +/* +** add length modifier into integer formats +*/ static void addintlen (char *form) { size_t l = strlen(form); char spec = form[l - 1]; @@ -783,6 +804,7 @@ static void addintlen (char *form) { static int str_format (lua_State *L) { + int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); @@ -796,12 +818,14 @@ static int str_format (lua_State *L) { luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ - char buff[MAX_ITEM]; /* to store the formatted item */ - arg++; + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - sprintf(buff, form, luaL_checkint(L, arg)); + nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'd': case 'i': @@ -810,17 +834,17 @@ static int str_format (lua_State *L) { LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n : (LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n; addintlen(form); - sprintf(buff, form, r); + nb = sprintf(buff, form, r); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - sprintf(buff, form, (double)luaL_checknumber(L, arg)); + nb = sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); - continue; /* skip the 'addsize' at the end */ + break; } case 's': { size_t l; @@ -830,10 +854,10 @@ static int str_format (lua_State *L) { keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); - continue; /* skip the `addsize' at the end */ + break; } else { - sprintf(buff, form, s); + nb = sprintf(buff, form, s); break; } } @@ -842,13 +866,15 @@ static int str_format (lua_State *L) { LUA_QL("format"), *(strfrmt - 1)); } } - luaL_addlstring(&b, buff, strlen(buff)); + luaL_addsize(&b, nb); } } luaL_pushresult(&b); return 1; } +/* }====================================================== */ + static const luaL_Reg strlib[] = { {"byte", str_byte}, diff --git a/src/ltable.c b/src/ltable.c index 78ff1d74..dc6604dd 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.47 2009/12/17 15:46:44 roberto Exp $ +** $Id: ltable.c,v 2.50 2010/04/18 13:22:48 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -31,6 +31,7 @@ #include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" #include "ltable.h" @@ -108,6 +109,8 @@ static Node *mainposition (const Table *t, const TValue *key) { return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: return hashpointer(t, pvalue(key)); + case LUA_TLCF: + return hashpointer(t, fvalue(key)); default: return hashpointer(t, gcvalue(key)); } @@ -452,7 +455,7 @@ const TValue *luaH_getint (Table *t, int key) { const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) + if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); diff --git a/src/ltablib.c b/src/ltablib.c index 6ad6b8e0..2e00da29 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.54 2010/01/13 19:59:10 roberto Exp $ +** $Id: ltablib.c,v 1.55 2010/03/13 03:57:46 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -171,15 +171,15 @@ static int tconcat (lua_State *L) { static int pack (lua_State *L) { int top = lua_gettop(L); lua_createtable(L, top, 1); /* create result table */ - /* use function environment as a temporary place to keep new table */ - lua_replace(L, LUA_ENVIRONINDEX); lua_pushinteger(L, top); /* number of elements */ - lua_setfield(L, LUA_ENVIRONINDEX, "n"); /* t.n = number of elements */ - for (; top >= 1; top--) /* assign elements */ - lua_rawseti(L, LUA_ENVIRONINDEX, top); - lua_pushvalue(L, LUA_ENVIRONINDEX); /* return new table */ - /* remove new table from environment to allow its later collection */ - lua_copy(L, LUA_REGISTRYINDEX, LUA_ENVIRONINDEX); + lua_setfield(L, -2, "n"); /* t.n = number of elements */ + if (top > 0) { /* at least one element? */ + lua_pushvalue(L, 1); + lua_rawseti(L, -2, 1); /* insert first element */ + lua_replace(L, 1); /* move table into its position (index 1) */ + for (; top >= 2; top--) /* assign other elements */ + lua_rawseti(L, 1, top); + } return 1; } @@ -328,7 +328,7 @@ LUAMOD_API int luaopen_table (lua_State *L) { #if defined(LUA_COMPAT_UNPACK) /* _G.unpack = table.unpack */ lua_getfield(L, -1, "unpack"); - lua_setfield(L, LUA_ENVIRONINDEX, "unpack"); + lua_setglobal(L, "unpack"); #endif return 1; } @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.11 2010/01/13 16:18:25 roberto Exp $ +** $Id: ltm.c,v 2.12 2010/04/13 20:48:12 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -70,7 +70,7 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { mt = uvalue(o)->metatable; break; default: - mt = G(L)->mt[ttype(o)]; + mt = G(L)->mt[ttypenv(o)]; } return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.9 2010/01/13 16:18:25 roberto Exp $ +** $Id: ltm.h,v 2.10 2010/04/13 20:48:12 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -43,7 +43,8 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) -#define typename(x) luaT_typenames_[(x) + 1] +#define ttypename(x) luaT_typenames_[(x) + 1] +#define objtypename(x) ttypename(ttypenv(x)) LUAI_DDEC const char *const luaT_typenames_[]; @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.182 2009/12/22 16:47:12 roberto Exp $ +** $Id: lua.c,v 1.190 2010/04/14 15:14:21 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -102,26 +102,31 @@ static void laction (int i) { } -static void print_usage (void) { - fprintf(stderr, +static void print_usage (const char *badoption) { + if (badoption[1] == 'e' || badoption[1] == 'l') { + luai_writestringerror("%s: ", progname); + luai_writestringerror("'%s' needs argument\n", badoption); + } else { + luai_writestringerror("%s: ", progname); + luai_writestringerror("unrecognized option '%s'\n", badoption); + } + luai_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" - " -l name require library " LUA_QL("name") "\n" " -i enter interactive mode after executing " LUA_QL("script") "\n" + " -l name require library " LUA_QL("name") "\n" " -v show version information\n" " -- stop handling options\n" - " - execute stdin and stop handling options\n" + " - stop handling options and execute stdin\n" , progname); - fflush(stderr); } static void l_message (const char *pname, const char *msg) { - if (pname) fprintf(stderr, "%s: ", pname); - fprintf(stderr, "%s\n", msg); - fflush(stderr); + if (pname) luai_writestringerror("%s: ", pname); + luai_writestringerror("%s\n", msg); } @@ -214,7 +219,7 @@ static int dostring (lua_State *L, const char *s, const char *name) { static int dolibrary (lua_State *L, const char *name) { - lua_getfield(L, LUA_ENVIRONINDEX, "require"); + lua_getglobal(L, "require"); lua_pushstring(L, name); return report(L, docall(L, 1, 1)); } @@ -222,7 +227,7 @@ static int dolibrary (lua_State *L, const char *name) { static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_getfield(L, LUA_ENVIRONINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ @@ -296,7 +301,7 @@ static void dotty (lua_State *L) { report(L, status); if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); - lua_getfield(L, LUA_ENVIRONINDEX, "print"); + lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) l_message(progname, lua_pushfstring(L, @@ -306,7 +311,6 @@ static void dotty (lua_State *L) { } lua_settop(L, 0); /* clear stack */ luai_writestring("\n", 1); - fflush(stdout); progname = oldprogname; } @@ -315,7 +319,7 @@ static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ - lua_setfield(L, LUA_ENVIRONINDEX, "arg"); + lua_setglobal(L, "arg"); fname = argv[n]; if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ @@ -356,10 +360,11 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { case 'l': if (argv[i][2] == '\0') { i++; - if (argv[i] == NULL) return -1; + if (argv[i] == NULL) return -(i - 1); } break; - default: return -1; /* invalid option */ + default: /* invalid option; return its index... */ + return -i; /* ...as a negative value */ } } return 0; @@ -369,7 +374,6 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { - if (argv[i] == NULL) continue; lua_assert(argv[i][0] == '-'); switch (argv[i][1]) { /* option */ case 'e': { @@ -412,8 +416,8 @@ static int pmain (lua_State *L) { int has_i = 0, has_v = 0, has_e = 0; if (argv[0] && argv[0][0]) progname = argv[0]; script = collectargs(argv, &has_i, &has_v, &has_e); - if (script < 0) { /* invalid args? */ - print_usage(); + if (script < 0) { /* invalid arg? */ + print_usage(argv[-script]); return 0; } if (has_v) print_version(); @@ -443,7 +447,6 @@ static int pmain (lua_State *L) { int main (int argc, char **argv) { - static lua_CFunction ppmain = &pmain; int status, result; lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { @@ -451,11 +454,10 @@ int main (int argc, char **argv) { return EXIT_FAILURE; } /* call 'pmain' in protected mode */ - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); /* calling function */ - lua_pushlightuserdata(L, &ppmain); - lua_pushinteger(L, argc); - lua_pushlightuserdata(L, argv); - status = lua_pcall(L, 3, 1, 0); + lua_pushcfunction(L, &pmain); + lua_pushinteger(L, argc); /* 1st argument */ + lua_pushlightuserdata(L, argv); /* 2nd argument */ + status = lua_pcall(L, 2, 1, 0); result = lua_toboolean(L, -1); /* get result */ finalreport(L, status); lua_close(L); @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.261 2010/01/11 17:15:11 roberto Exp $ +** $Id: lua.h,v 1.270 2010/05/12 14:09:20 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,7 +17,7 @@ #define LUA_VERSION "Lua 5.2" -#define LUA_RELEASE "Lua 5.2.0 (work2)" +#define LUA_RELEASE "Lua 5.2.0 (work3)" #define LUA_VERSION_NUM 502 #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -34,8 +34,7 @@ ** pseudo-indices */ #define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX -#define LUA_ENVIRONINDEX (LUA_REGISTRYINDEX - 1) -#define lua_upvalueindex(i) (LUA_ENVIRONINDEX - (i)) +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) /* thread status */ @@ -82,6 +81,8 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 +#define LUA_NUMTAGS 9 + /* minimum Lua stack available to a C function */ @@ -90,8 +91,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* predefined values in the registry */ #define LUA_RIDX_MAINTHREAD 1 -#define LUA_RIDX_CPCALL 2 -#define LUA_RIDX_GLOBALS 3 +#define LUA_RIDX_GLOBALS 2 #define LUA_RIDX_LAST LUA_RIDX_GLOBALS @@ -129,6 +129,7 @@ LUA_API const lua_Number *(lua_version) (lua_State *L); /* ** basic stack manipulation */ +LUA_API int (lua_absindex) (lua_State *L, int idx); LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); @@ -212,7 +213,7 @@ LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API void (lua_getfenv) (lua_State *L, int idx); +LUA_API void (lua_getenv) (lua_State *L, int idx); /* @@ -223,7 +224,7 @@ LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API int (lua_setfenv) (lua_State *L, int idx); +LUA_API void (lua_setenv) (lua_State *L, int idx); /* @@ -267,6 +268,8 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 #define LUA_GCISRUNNING 8 +#define LUA_GCGEN 9 +#define LUA_GCINC 10 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -297,11 +300,14 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_newtable(L) lua_createtable(L, 0, 0) -#define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, (s)) -#define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, (s)) +#define lua_setglobal(L,s) \ + (lua_pushglobaltable(L), lua_pushvalue(L, -2), \ + lua_setfield(L, -2, (s)), lua_pop(L, 2)) + +#define lua_getglobal(L,s) \ + (lua_pushglobaltable(L), lua_getfield(L, -1, (s)), lua_remove(L, -2)) -#define lua_register(L,n,f) \ - (lua_pushcfunction(L, (f)), lua_setfield(L, LUA_ENVIRONINDEX, (n))) +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.57 2008/03/26 13:40:18 lhf Exp $ +** $Id: luac.c,v 1.61 2010/05/14 11:40:22 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -60,7 +60,7 @@ static void usage(const char* message) " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n" - " - process stdin and stop handling options\n" + " - stop handling options and process stdin\n" ,progname,Output); exit(EXIT_FAILURE); } @@ -89,7 +89,7 @@ static int doargs(int argc, char* argv[]) else if (IS("-o")) /* output file */ { output=argv[++i]; - if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument"); + if (output==NULL || *output==0 || *output=='-') usage(LUA_QL("-o") " needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ @@ -150,16 +150,10 @@ static int writer(lua_State* L, const void* p, size_t size, void* u) return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } -struct Smain { - int argc; - char** argv; -}; - static int pmain(lua_State* L) { - struct Smain* s = (struct Smain*)lua_touserdata(L, 1); - int argc=s->argc; - char** argv=s->argv; + int argc=lua_tointeger(L,1); + char** argv=lua_touserdata(L,2); const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); @@ -183,25 +177,18 @@ static int pmain(lua_State* L) return 0; } -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); - lua_pushlightuserdata(L, &func); - lua_pushlightuserdata(L, ud); - return lua_pcall(L, 2, 0, 0); -} - int main(int argc, char* argv[]) { lua_State* L; - struct Smain s; int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); L=luaL_newstate(); if (L==NULL) fatal("not enough memory for state"); - s.argc=argc; - s.argv=argv; - if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); + lua_pushcfunction(L,&pmain); + lua_pushinteger(L,argc); + lua_pushlightuserdata(L,argv); + if (lua_pcall(L,2,0,0)!=0) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } diff --git a/src/luaconf.h b/src/luaconf.h index b16e9991..0606230d 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.130 2010/01/11 17:15:30 roberto Exp $ +** $Id: luaconf.h,v 1.137 2010/05/12 14:17:36 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -89,7 +89,7 @@ #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" -#else +#else /* _WIN32 */ #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/5.2/" #define LUA_CDIR LUA_ROOT "lib/lua/5.2/" @@ -98,7 +98,7 @@ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" -#endif +#endif /* _WIN32 */ /* @@ -130,11 +130,12 @@ #define LUA_API __declspec(dllimport) #endif -#else +#else /* LUA_BUILD_AS_DLL */ #define LUA_API extern -#endif +#endif /* LUA_BUILD_AS_DLL */ + /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API @@ -166,11 +167,11 @@ #define LUAI_DDEC LUAI_FUNC #define LUAI_DDEF /* empty */ -#else +#else /* luaall_c */ #define LUAI_FUNC extern #define LUAI_DDEC extern #define LUAI_DDEF /* empty */ -#endif +#endif /* luaall_c */ @@ -192,10 +193,17 @@ /* @@ luai_writestring defines how 'print' prints its results. -** CHANGE it if your system does not have a useful stdout. */ +#include <stdio.h> #define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +/* +@@ luai_writestringerror defines how to print error messages. +** (A format string with one argument is enough for Lua...) +*/ +#define luai_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) + @@ -220,18 +228,12 @@ #define LUA_COMPAT_UNPACK /* -@@ LUA_COMPAT_CPCALL controls the presence of function 'lua_cpcall'. +@@ LUA_COMPAT_CPCALL controls the presence of macro 'lua_cpcall'. ** You can replace it with the preregistered function 'cpcall'. */ -#define LUA_COMPAT_CPCALL -LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +#define lua_cpcall(L,f,u) \ + (lua_pushlightuserdata(L,(u)), luaL_cpcall(L,(f),1,0)) -/* -@@ LUA_COMPAT_FENV controls the presence of functions 'setfenv/getfenv'. -** You can replace them with lexical environments, 'loadin', or the -** debug library. -*/ -#define LUA_COMPAT_FENV /* @@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. @@ -267,7 +269,7 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* compatibility with previous wrong spelling */ #define luaL_typerror luaL_typeerror -#endif +#endif /* LUA_COMPAT_ALL */ /* }================================================================== */ @@ -421,7 +423,7 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* @@ lua_number2int is a macro to convert lua_Number to int. -@@ lua_number2integer is a macro to convert lua_Number to lUA_INTEGER. +@@ lua_number2integer is a macro to convert lua_Number to LUA_INTEGER. @@ lua_number2uint is a macro to convert a lua_Number to an unsigned @* LUA_INT32. @@ lua_uint2number is a macro to convert an unsigned LUA_INT32 @@ -439,30 +441,31 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) -#define lua_number2int(i,d) {__asm fld d __asm fistp i} +#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} #define lua_number2integer(i,n) lua_number2int(i, n) -#define lua_number2uint(i,n) lua_number2int(i, n) +#define lua_number2uint(i,n) \ + {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} -#else +#else /* _MSC_VER */ /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ union luai_Cast { double l_d; long l_l; }; -#define lua_number2int(i,d) \ - { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } +#define lua_number2int(i,n) \ + { volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) #define lua_number2uint(i,n) lua_number2int(i, n) -#endif +#endif /* _MSC_VER */ -#else +#else /* LUA_NUMBER_DOUBLE ... (Pentium) */ /* this option always works, but may be slow */ -#define lua_number2int(i,d) ((i)=(int)(d)) -#define lua_number2integer(i,d) ((i)=(LUA_INTEGER)(d)) -#define lua_number2uint(i,d) ((i)=(unsigned LUA_INT32)(d)) +#define lua_number2int(i,n) ((i)=(int)(n)) +#define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n)) +#define lua_number2uint(i,n) ((i)=(unsigned LUA_INT32)(n)) -#endif +#endif /* LUA_NUMBER_DOUBLE ... (Pentium) */ /* on several machines, coercion from unsigned to double is too slow, @@ -483,11 +486,11 @@ union luai_Cast { double l_d; long l_l; }; #include <float.h> #include <math.h> -#define luai_hashnum(i,d) { int e; \ - d = frexp(d, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ - lua_number2int(i, d); i += e; } +#define luai_hashnum(i,n) { int e; \ + n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + lua_number2int(i, n); i += e; } -#endif +#endif /* ltable_c */ /* }================================================================== */ diff --git a/src/lundump.c b/src/lundump.c index 244d6e52..e82e1951 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ +** $Id: lundump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -180,7 +180,6 @@ static Proto* LoadFunction(LoadState* S, TString* p) f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); - f->envreg=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); LoadUpvalues(S,f); @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.102 2009/12/17 16:20:01 roberto Exp $ +** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -50,8 +50,8 @@ int luaV_tostring (lua_State *L, StkId obj) { else { char s[LUAI_MAXNUMBER2STR]; lua_Number n = nvalue(obj); - lua_number2str(s, n); - setsvalue2s(L, obj, luaS_new(L, s)); + int l = lua_number2str(s, n); + setsvalue2s(L, obj, luaS_newlstr(L, s, l)); return 1; } } @@ -74,6 +74,10 @@ static void traceexec (lua_State *L) { luaD_hook(L, LUA_HOOKLINE, newline); } L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + luaD_throw(L, LUA_YIELD); + } } @@ -102,7 +106,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is no nil? */ + if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; @@ -129,7 +133,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ - if (!ttisnil(oldval) || /* result is no nil? */ + if (!ttisnil(oldval) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); @@ -157,12 +161,13 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; + if (event == TM_UNM) p2 = luaO_nilobject; callTM(L, tm, p1, p2, res, 1); return 1; } -static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, +static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TValue *tm1 = fasttm(L, mt1, event); const TValue *tm2; @@ -178,14 +183,10 @@ static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - const TValue *tm1 = luaT_gettmbyobj(L, p1, event); - const TValue *tm2; - if (ttisnil(tm1)) return -1; /* no metamethod? */ - tm2 = luaT_gettmbyobj(L, p2, event); - if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ - return -1; - callTM(L, tm1, p1, p2, L->top, 1); - return !l_isfalse(L->top); + if (!call_binTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } @@ -213,11 +214,9 @@ static int l_strcmp (const TString *ls, const TString *rs) { int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) + if (ttisnumber(l) && ttisnumber(r)) return luai_numlt(L, nvalue(l), nvalue(r)); - else if (ttisstring(l)) + else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; @@ -227,11 +226,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) + if (ttisnumber(l) && ttisnumber(r)) return luai_numle(L, nvalue(l), nvalue(r)); - else if (ttisstring(l)) + else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; @@ -249,14 +246,16 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); + tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; - tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); @@ -354,14 +353,10 @@ void luaV_finishOp (lua_State *L) { StkId base = ci->u.l.base; Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); - if (op == OP_EXTRAARG) { /* extra argument? */ - inst = *(ci->u.l.savedpc - 2); /* get its 'main' instruction */ - op = GET_OPCODE(inst); - } switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: - case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { + case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; } @@ -402,7 +397,7 @@ void luaV_finishOp (lua_State *L) { L->top = ci->top; /* adjust results */ break; } - case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE: + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } @@ -426,11 +421,13 @@ void luaV_finishOp (lua_State *L) { (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) -#define dojump(i) { ci->u.l.savedpc += (i); luai_threadyield(L);} +#define dojump(i) (ci->u.l.savedpc += (i)) #define Protect(x) { {x;}; base = ci->u.l.base; } +#define checkGC(L) Protect(luaC_checkGC(L); luai_threadyield(L);) + #define arith_op(op,tm) { \ TValue *rb = RKB(i); \ @@ -439,133 +436,109 @@ void luaV_finishOp (lua_State *L) { lua_Number nb = nvalue(rb), nc = nvalue(rc); \ setnvalue(ra, op(L, nb, nc)); \ } \ - else \ - Protect(luaV_arith(L, ra, rb, rc, tm)); \ - } + else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } +#define vmdispatch(o) switch(o) +#define vmcase(l,b) case l: {b} break; void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; - LClosure *cl = &clvalue(ci->func)->l; - TValue *k = cl->p->k; - StkId base = ci->u.l.base; + LClosure *cl; + TValue *k; + StkId base; + newframe: /* reentry point when frame changes (call/return) */ lua_assert(isLua(ci)); + lua_assert(ci == L->ci); + cl = &clvalue(ci->func)->l; + k = cl->p->k; + base = ci->u.l.base; /* main loop of interpreter */ for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->status == LUA_YIELD) { /* did hook yield? */ - ci->u.l.savedpc--; /* undo increment */ - luaD_throw(L, LUA_YIELD); - } - base = ci->u.l.base; + Protect(traceexec(L)); } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); - switch (GET_OPCODE(i)) { - case OP_MOVE: { + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE, setobjs2s(L, ra, RB(i)); - continue; - } - case OP_LOADK: { + ) + vmcase(OP_LOADK, TValue *rb = KBx(i); setobj2s(L, ra, rb); - continue; - } - case OP_LOADBOOL: { + ) + vmcase(OP_LOADBOOL, setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - continue; - } - case OP_LOADNIL: { + ) + vmcase(OP_LOADNIL, TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); - continue; - } - case OP_GETUPVAL: { + ) + vmcase(OP_GETUPVAL, int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); - continue; - } - case OP_GETGLOBAL: { - TValue g; - TValue *rb = KBx(i); - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(rb)); - Protect(luaV_gettable(L, &g, rb, ra)); - continue; - } - case OP_GETTABLE: { + ) + vmcase(OP_GETTABUP, + int b = GETARG_B(i); + Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); + ) + vmcase(OP_GETTABLE, Protect(luaV_gettable(L, RB(i), RKC(i), ra)); - continue; - } - case OP_SETGLOBAL: { - TValue g; - TValue *rb = KBx(i); - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(rb)); - Protect(luaV_settable(L, &g, rb, ra)); - continue; - } - case OP_SETUPVAL: { + ) + vmcase(OP_SETTABUP, + int a = GETARG_A(i); + Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); + ) + vmcase(OP_SETUPVAL, UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); - continue; - } - case OP_SETTABLE: { + ) + vmcase(OP_SETTABLE, Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - continue; - } - case OP_NEWTABLE: { + ) + vmcase(OP_NEWTABLE, int b = GETARG_B(i); int c = GETARG_C(i); Table *t = luaH_new(L); sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - Protect(luaC_checkGC(L)); - continue; - } - case OP_SELF: { + checkGC(L); + ) + vmcase(OP_SELF, StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); - continue; - } - case OP_ADD: { + ) + vmcase(OP_ADD, arith_op(luai_numadd, TM_ADD); - continue; - } - case OP_SUB: { + ) + vmcase(OP_SUB, arith_op(luai_numsub, TM_SUB); - continue; - } - case OP_MUL: { + ) + vmcase(OP_MUL, arith_op(luai_nummul, TM_MUL); - continue; - } - case OP_DIV: { + ) + vmcase(OP_DIV, arith_op(luai_numdiv, TM_DIV); - continue; - } - case OP_MOD: { + ) + vmcase(OP_MOD, arith_op(luai_nummod, TM_MOD); - continue; - } - case OP_POW: { + ) + vmcase(OP_POW, arith_op(luai_numpow, TM_POW); - continue; - } - case OP_UNM: { + ) + vmcase(OP_UNM, TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); @@ -574,31 +547,26 @@ void luaV_execute (lua_State *L) { else { Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); } - continue; - } - case OP_NOT: { + ) + vmcase(OP_NOT, int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); - continue; - } - case OP_LEN: { + ) + vmcase(OP_LEN, Protect(luaV_objlen(L, ra, RB(i))); - continue; - } - case OP_CONCAT: { + ) + vmcase(OP_CONCAT, int b = GETARG_B(i); int c = GETARG_C(i); L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c-b+1); luaC_checkGC(L)); + Protect(luaV_concat(L, c-b+1); checkGC(L);) L->top = ci->top; /* restore top */ setobjs2s(L, RA(i), base+b); - continue; - } - case OP_JMP: { + ) + vmcase(OP_JMP, dojump(GETARG_sBx(i)); - continue; - } - case OP_EQ: { + ) + vmcase(OP_EQ, TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( @@ -606,62 +574,54 @@ void luaV_execute (lua_State *L) { dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_LT: { + ) + vmcase(OP_LT, Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_LE: { + ) + vmcase(OP_LE, Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_TEST: { + ) + vmcase(OP_TEST, if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ci->u.l.savedpc++; - continue; - } - case OP_TESTSET: { + ) + vmcase(OP_TESTSET, TValue *rb = RB(i); if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) { setobjs2s(L, ra, rb); dojump(GETARG_sBx(*ci->u.l.savedpc)); } ci->u.l.savedpc++; - continue; - } - case OP_CALL: { + ) + vmcase(OP_CALL, int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (luaD_precall(L, ra, nresults)) { /* C function? */ if (nresults >= 0) L->top = ci->top; /* adjust results */ base = ci->u.l.base; - continue; } else { /* Lua function */ ci = L->ci; ci->callstatus |= CIST_REENTRY; - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_TAILCALL: { + ) + vmcase(OP_TAILCALL, int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */ base = ci->u.l.base; - continue; - } else { /* tail call: put called frame (n) in place of caller one (o) */ CallInfo *nci = L->ci; /* called frame */ @@ -682,10 +642,10 @@ void luaV_execute (lua_State *L) { oci->callstatus |= CIST_TAIL; /* function was tail called */ ci = L->ci = oci; /* remove new frame */ lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_RETURN: { + ) + vmcase(OP_RETURN, int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (cl->p->sizep > 0) luaF_close(L, base); @@ -697,10 +657,10 @@ void luaV_execute (lua_State *L) { if (b) L->top = ci->top; lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_FORLOOP: { + ) + vmcase(OP_FORLOOP, lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); @@ -710,9 +670,8 @@ void luaV_execute (lua_State *L) { setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } - continue; - } - case OP_FORPREP: { + ) + vmcase(OP_FORPREP, const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; @@ -724,9 +683,8 @@ void luaV_execute (lua_State *L) { luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); dojump(GETARG_sBx(i)); - continue; - } - case OP_TFORCALL: { + ) + vmcase(OP_TFORCALL, StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); @@ -737,16 +695,16 @@ void luaV_execute (lua_State *L) { i = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - /* go through */ - } - case OP_TFORLOOP: { + goto l_tforloop; + ) + vmcase(OP_TFORLOOP, + l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ dojump(GETARG_sBx(i)); /* jump back */ } - continue; - } - case OP_SETLIST: { + ) + vmcase(OP_SETLIST, int n = GETARG_B(i); int c = GETARG_C(i); int last; @@ -759,45 +717,34 @@ void luaV_execute (lua_State *L) { h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* pre-alloc it at once */ + luaH_resizearray(L, h, last); /* pre-allocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setint(L, h, last--), val); luaC_barriert(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ - continue; - } - case OP_CLOSE: { + ) + vmcase(OP_CLOSE, luaF_close(L, ra); - continue; - } - case OP_CLOSURE: { + ) + vmcase(OP_CLOSURE, Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ int nup = p->sizeupvalues; - Closure *ncl = luaF_newLclosure(L, nup, cl->env); + Closure *ncl = luaF_newLclosure(L, nup); Upvaldesc *uv = p->upvalues; int j; ncl->l.p = p; setclvalue(L, ra, ncl); /* anchor new closure in stack */ - if (p->envreg != NO_REG) { /* lexical environment? */ - StkId env = base + p->envreg; - if (!ttistable(env)) - luaG_runerror(L, "environment is not a table: " - "cannot create closure"); - else - ncl->l.env = hvalue(env); - } for (j = 0; j < nup; j++) { /* fill in upvalues */ if (uv[j].instack) /* upvalue refers to local variable? */ ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx); else /* get upvalue from enclosing function */ ncl->l.upvals[j] = cl->upvals[uv[j].idx]; } - Protect(luaC_checkGC(L)); - continue; - } - case OP_VARARG: { + checkGC(L); + ) + vmcase(OP_VARARG, int b = GETARG_B(i) - 1; int j; int n = cast_int(base - ci->func) - cl->p->numparams - 1; @@ -815,18 +762,11 @@ void luaV_execute (lua_State *L) { setnilvalue(ra + j); } } - continue; - } - case OP_EXTRAARG: { - luaG_runerror(L, "bad opcode"); - return; - } + ) + vmcase(OP_EXTRAARG, + lua_assert(0); + ) } - /* function changed (call/return): update pointers */ - lua_assert(ci == L->ci); - cl = &clvalue(ci->func)->l; - k = cl->p->k; - base = ci->u.l.base; } } diff --git a/src/print.c b/src/print.c index fb491e7e..6a5b05db 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.58 2008/09/11 12:05:06 lhf Exp $ +** $Id: print.c,v 1.60 2010/05/17 22:27:10 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -82,6 +82,7 @@ static void PrintCode(const Proto* f) int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); + int ax=GETARG_Ax(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); int line=getfuncline(f,pc); @@ -99,24 +100,32 @@ static void PrintCode(const Proto* f) if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); break; case iABx: - if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); + if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx); break; case iAsBx: if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); break; + case iAx: + printf("%d",ax); + break; } switch (o) { case OP_LOADK: - printf("\t; "); PrintConstant(f,bx); + printf("\t; "); PrintConstant(f,bx-1); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); break; - case OP_GETGLOBAL: - case OP_SETGLOBAL: - printf("\t; %s",svalue(&f->k[bx])); + case OP_GETTABUP: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABUP: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[a].name) : "-"); + if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_GETTABLE: case OP_SELF: |