summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLua Team <team@lua.org>2010-05-18 12:00:00 +0000
committerrepogen <>2010-05-18 12:00:00 +0000
commitf970e1e83ed07bbcf8a20fc1a95f91a0a2aae620 (patch)
tree005b26e8ebf7553ba5c7a66700866be3e42443d0 /src
parentecd48c2901f08a88db32139b97c35c59eba1f19e (diff)
downloadlua-github-f970e1e83ed07bbcf8a20fc1a95f91a0a2aae620.tar.gz
Lua 5.2.0-work35.2.0-work3
Diffstat (limited to 'src')
-rw-r--r--src/Makefile10
-rw-r--r--src/lapi.c240
-rw-r--r--src/lauxlib.c201
-rw-r--r--src/lauxlib.h39
-rw-r--r--src/lbaselib.c95
-rw-r--r--src/lbitlib.c34
-rw-r--r--src/lcode.c51
-rw-r--r--src/lcode.h8
-rw-r--r--src/ldblib.c30
-rw-r--r--src/ldebug.c116
-rw-r--r--src/ldo.c75
-rw-r--r--src/ldump.c3
-rw-r--r--src/lfunc.c23
-rw-r--r--src/lfunc.h6
-rw-r--r--src/lgc.c692
-rw-r--r--src/lgc.h91
-rw-r--r--src/linit.c9
-rw-r--r--src/liolib.c129
-rw-r--r--src/llex.c116
-rw-r--r--src/llex.h3
-rw-r--r--src/llimits.h13
-rw-r--r--src/lmem.c29
-rw-r--r--src/lmem.h4
-rw-r--r--src/loadlib.c31
-rw-r--r--src/lobject.c38
-rw-r--r--src/lobject.h58
-rw-r--r--src/lopcodes.c10
-rw-r--r--src/lopcodes.h9
-rw-r--r--src/lparser.c184
-rw-r--r--src/lparser.h11
-rw-r--r--src/lstate.c80
-rw-r--r--src/lstate.h34
-rw-r--r--src/lstring.c8
-rw-r--r--src/lstring.h12
-rw-r--r--src/lstrlib.c132
-rw-r--r--src/ltable.c7
-rw-r--r--src/ltablib.c20
-rw-r--r--src/ltm.c4
-rw-r--r--src/ltm.h5
-rw-r--r--src/lua.c52
-rw-r--r--src/lua.h30
-rw-r--r--src/luac.c31
-rw-r--r--src/luaconf.h71
-rw-r--r--src/lundump.c3
-rw-r--r--src/lvm.c334
-rw-r--r--src/print.c21
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
diff --git a/src/lapi.c b/src/lapi.c
index 56c0c1e9..8a0378f9 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -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
diff --git a/src/ldo.c b/src/ldo.c
index 4890ce21..5b0e766e 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -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);
diff --git a/src/lgc.c b/src/lgc.c
index 2094d386..276edacd 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -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);
}
/* }====================================================== */
diff --git a/src/lgc.h b/src/lgc.h
index bab2e850..18eb70fd 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -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;
}
diff --git a/src/llex.c b/src/llex.c
index 3cfdbca1..e380910d 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -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;
}
}
}
diff --git a/src/llex.h b/src/llex.h
index d687fb8d..1a811dce 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -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)
diff --git a/src/lmem.c b/src/lmem.c
index 022ccfd3..0f3178a2 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -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;
}
diff --git a/src/lmem.h b/src/lmem.h
index b8b3bae9..ff324f89 100644
--- a/src/lmem.h
+++ b/src/lmem.h
@@ -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;
}
diff --git a/src/ltm.c b/src/ltm.c
index 3a9e73ca..faa8f57d 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -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);
}
diff --git a/src/ltm.h b/src/ltm.h
index 732aa12d..05abc40b 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -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_[];
diff --git a/src/lua.c b/src/lua.c
index 757adb6c..2b1c6161 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -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);
diff --git a/src/lua.h b/src/lua.h
index f79df970..09a9ab76 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -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)
diff --git a/src/luac.c b/src/luac.c
index 451bfffc..ee2026ba 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -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);
diff --git a/src/lvm.c b/src/lvm.c
index a3150888..518a16ba 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -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: