diff options
author | Lua Team <team@lua.org> | 2004-03-24 12:00:00 +0000 |
---|---|---|
committer | repogen <> | 2004-03-24 12:00:00 +0000 |
commit | ced7bbbe7a257ce6de94069d5dbf6672aeafd4d9 (patch) | |
tree | 2a01a79e6a4f451dccd247c70310ad957204cefa /src | |
parent | e7731a8fb8a317aa5c444ef073bfad82fa5baa54 (diff) | |
download | lua-github-ced7bbbe7a257ce6de94069d5dbf6672aeafd4d9.tar.gz |
Lua 5.1-work05.1-work0
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 2 | ||||
l--------- | src/RCS | 1 | ||||
-rw-r--r-- | src/lapi.c | 430 | ||||
-rw-r--r-- | src/lapi.h | 4 | ||||
-rw-r--r-- | src/lcode.c | 52 | ||||
-rw-r--r-- | src/ldebug.c | 113 | ||||
-rw-r--r-- | src/ldebug.h | 9 | ||||
-rw-r--r-- | src/ldo.c | 141 | ||||
-rw-r--r-- | src/ldo.h | 8 | ||||
-rw-r--r-- | src/ldump.c | 22 | ||||
-rw-r--r-- | src/lfunc.c | 66 | ||||
-rw-r--r-- | src/lfunc.h | 12 | ||||
-rw-r--r-- | src/lgc.c | 669 | ||||
-rw-r--r-- | src/lgc.h | 81 | ||||
l--------- | src/lib/RCS | 1 | ||||
-rw-r--r-- | src/lib/lauxlib.c | 125 | ||||
-rw-r--r-- | src/lib/lbaselib.c | 139 | ||||
-rw-r--r-- | src/lib/ldblib.c | 150 | ||||
-rw-r--r-- | src/lib/liolib.c | 130 | ||||
-rw-r--r-- | src/lib/lmathlib.c | 14 | ||||
-rw-r--r-- | src/lib/loadlib.c | 26 | ||||
-rw-r--r-- | src/lib/lstrlib.c | 54 | ||||
-rw-r--r-- | src/lib/ltablib.c | 6 | ||||
-rw-r--r-- | src/llex.c | 449 | ||||
-rw-r--r-- | src/llex.h | 6 | ||||
-rw-r--r-- | src/llimits.h | 65 | ||||
-rw-r--r-- | src/lmem.c | 82 | ||||
-rw-r--r-- | src/lobject.c | 48 | ||||
-rw-r--r-- | src/lobject.h | 122 | ||||
-rw-r--r-- | src/lopcodes.c | 87 | ||||
-rw-r--r-- | src/lopcodes.h | 45 | ||||
-rw-r--r-- | src/lparser.c | 254 | ||||
-rw-r--r-- | src/lparser.h | 16 | ||||
-rw-r--r-- | src/lstate.c | 171 | ||||
-rw-r--r-- | src/lstate.h | 64 | ||||
-rw-r--r-- | src/lstring.c | 37 | ||||
-rw-r--r-- | src/lstring.h | 6 | ||||
-rw-r--r-- | src/ltable.c | 109 | ||||
-rw-r--r-- | src/ltable.h | 15 | ||||
-rw-r--r-- | src/ltm.c | 22 | ||||
-rw-r--r-- | src/ltm.h | 10 | ||||
l--------- | src/lua/RCS | 1 | ||||
-rw-r--r-- | src/lua/README | 2 | ||||
-rw-r--r-- | src/lua/lua.c | 13 | ||||
-rw-r--r-- | src/luac/Makefile | 8 | ||||
l--------- | src/luac/RCS | 1 | ||||
-rw-r--r-- | src/luac/README | 2 | ||||
-rw-r--r-- | src/luac/luac.c | 77 | ||||
-rw-r--r-- | src/luac/print.c | 39 | ||||
-rw-r--r-- | src/lundump.c | 89 | ||||
-rw-r--r-- | src/lundump.h | 11 | ||||
-rw-r--r-- | src/lvm.c | 488 | ||||
-rw-r--r-- | src/lvm.h | 15 | ||||
-rw-r--r-- | src/lzio.c | 16 | ||||
-rw-r--r-- | src/lzio.h | 18 |
55 files changed, 2561 insertions, 2082 deletions
diff --git a/src/Makefile b/src/Makefile index bf64c03f..7812b918 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,6 @@ OBJS= \ lstate.o \ lstring.o \ ltable.o \ - ltests.o \ ltm.o \ lundump.o \ lvm.o \ @@ -42,7 +41,6 @@ SRCS= \ lstate.c \ lstring.c \ ltable.c \ - ltests.c \ ltm.c \ lundump.c \ lvm.c \ diff --git a/src/RCS b/src/RCS new file mode 120000 index 00000000..1ae38936 --- /dev/null +++ b/src/RCS @@ -0,0 +1 @@ +../RCS
\ No newline at end of file @@ -1,11 +1,12 @@ /* -** $Id: lapi.c,v 1.235 2003/04/07 14:36:08 roberto Exp $ +** $Id: lapi.c,v 2.5 2004/03/23 17:07:34 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include <assert.h> +#include <stdarg.h> #include <string.h> #define lapi_c @@ -27,6 +28,12 @@ #include "lvm.h" +/* function to convert a lua_Number to lua_Integer (with any rounding method) */ +#ifndef lua_number2integer +#define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) +#endif + + const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" @@ -35,63 +42,44 @@ const char lua_ident[] = #ifndef api_check -#define api_check(L, o) /*{ assert(o); }*/ +#define api_check(L, o) lua_assert(o) #endif #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} +#define api_checkvalidindex(L, i) api_check(L, (i) != &luaO_nilobject) +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} -static TObject *negindex (lua_State *L, int idx) { - if (idx > LUA_REGISTRYINDEX) { +static TValue *luaA_index (lua_State *L, int idx) { + if (idx > 0) { + TValue *o = L->base + (idx - 1); + api_check(L, idx <= L->stack_last - L->base); + if (o >= L->top) return cast(TValue *, &luaO_nilobject); + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); - return L->top+idx; + return L->top + idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_GLOBALSINDEX: return gt(L); default: { - TObject *func = (L->base - 1); + Closure *func = curr_func(L); idx = LUA_GLOBALSINDEX - idx; - lua_assert(iscfunction(func)); - return (idx <= clvalue(func)->c.nupvalues) - ? &clvalue(func)->c.upvalue[idx-1] - : NULL; + return (idx <= func->c.nupvalues) + ? &func->c.upvalue[idx-1] + : cast(TValue *, &luaO_nilobject); } } } -static TObject *luaA_index (lua_State *L, int idx) { - if (idx > 0) { - api_check(L, idx <= L->top - L->base); - return L->base + idx - 1; - } - else { - TObject *o = negindex(L, idx); - api_check(L, o != NULL); - return o; - } -} - - -static TObject *luaA_indexAcceptable (lua_State *L, int idx) { - if (idx > 0) { - TObject *o = L->base+(idx-1); - api_check(L, idx <= L->stack_last - L->base); - if (o >= L->top) return NULL; - else return o; - } - else - return negindex(L, idx); -} - - -void luaA_pushobject (lua_State *L, const TObject *o) { - setobj2s(L->top, o); +void luaA_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); incr_top(L); } @@ -114,11 +102,12 @@ LUA_API int lua_checkstack (lua_State *L, int size) { LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; + if (from == to) return; lua_lock(to); api_checknelems(from, n); from->top -= n; for (i = 0; i < n; i++) { - setobj2s(to->top, from->top + i); + setobj2s(to, to->top, from->top + i); api_incr_top(to); } lua_unlock(to); @@ -140,7 +129,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { lua_lock(L); luaC_checkGC(L); L1 = luaE_newthread(L); - setthvalue(L->top, L1); + setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); lua_userstateopen(L1); @@ -179,7 +168,8 @@ LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = luaA_index(L, idx); - while (++p < L->top) setobjs2s(p-1, p); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } @@ -190,16 +180,22 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId q; lua_lock(L); p = luaA_index(L, idx); - for (q = L->top; q>p; q--) setobjs2s(q, q-1); - setobjs2s(p, L->top); + api_checkvalidindex(L, p); + for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + setobjs2s(L, p, L->top); lua_unlock(L); } LUA_API void lua_replace (lua_State *L, int idx) { + StkId o; lua_lock(L); api_checknelems(L, 1); - setobj(luaA_index(L, idx), L->top - 1); /* write barrier */ + o = luaA_index(L, idx); + api_checkvalidindex(L, o); + setobj(L, o, L->top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L->top - 1); L->top--; lua_unlock(L); } @@ -207,7 +203,7 @@ LUA_API void lua_replace (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); - setobj2s(L->top, luaA_index(L, idx)); + setobj2s(L, L->top, luaA_index(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -220,8 +216,8 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? LUA_TNONE : ttype(o); + StkId o = luaA_index(L, idx); + return (o == &luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -232,15 +228,15 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? 0 : iscfunction(o); + StkId o = luaA_index(L, idx); + return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && tonumber(o, &n)); + TValue n; + const TValue *o = luaA_index(L, idx); + return tonumber(o, &n); } @@ -251,16 +247,16 @@ LUA_API int lua_isstring (lua_State *L, int idx) { LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && (ttisuserdata(o) || ttislightuserdata(o))); + const TValue *o = luaA_index(L, idx); + return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = luaA_indexAcceptable(L, index1); - StkId o2 = luaA_indexAcceptable(L, index2); - return (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : luaO_rawequalObj(o1, o2); + StkId o1 = luaA_index(L, index1); + StkId o2 = luaA_index(L, index2); + return (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); } @@ -268,10 +264,10 @@ LUA_API int lua_equal (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : equalobj(L, o1, o2); + o1 = luaA_index(L, index1); + o2 = luaA_index(L, index2); + i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + : equalobj(L, o1, o2); lua_unlock(L); return i; } @@ -281,10 +277,10 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out-of-range */ - : luaV_lessthan(L, o1, o2); + o1 = luaA_index(L, index1); + o2 = luaA_index(L, index2); + i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); lua_unlock(L); return i; } @@ -292,26 +288,37 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - if (o != NULL && tonumber(o, &n)) + TValue n; + const TValue *o = luaA_index(L, idx); + if (tonumber(o, &n)) return nvalue(o); else return 0; } +LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { + TValue n; + const TValue *o = luaA_index(L, idx); + if (tonumber(o, &n)) { + lua_Integer res; + lua_number2integer(res, nvalue(o)); + return res; + } + else + return 0; +} + + LUA_API int lua_toboolean (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL) && !l_isfalse(o); + const TValue *o = luaA_index(L, idx); + return !l_isfalse(o); } LUA_API const char *lua_tostring (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return NULL; - else if (ttisstring(o)) + StkId o = luaA_index(L, idx); + if (ttisstring(o)) return svalue(o); else { const char *s; @@ -325,15 +332,13 @@ LUA_API const char *lua_tostring (lua_State *L, int idx) { LUA_API size_t lua_strlen (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return 0; - else if (ttisstring(o)) - return tsvalue(o)->tsv.len; + StkId o = luaA_index(L, idx); + if (ttisstring(o)) + return tsvalue(o)->len; else { size_t l; lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->tsv.len : 0); + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); lua_unlock(L); return l; } @@ -341,16 +346,15 @@ LUA_API size_t lua_strlen (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f; + StkId o = luaA_index(L, idx); + return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; + StkId o = luaA_index(L, idx); switch (ttype(o)) { - case LUA_TUSERDATA: return (uvalue(o) + 1); + case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } @@ -358,24 +362,21 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o); + StkId o = luaA_index(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; - else { - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TFUNCTION: return clvalue(o); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); - default: return NULL; - } + StkId o = luaA_index(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; } } @@ -402,10 +403,18 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { } +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setnvalue(L->top, cast(lua_Number, n)); + api_incr_top(L); + lua_unlock(L); +} + + LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { lua_lock(L); luaC_checkGC(L); - setsvalue2s(L->top, luaS_newlstr(L, s, len)); + setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); api_incr_top(L); lua_unlock(L); } @@ -452,8 +461,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { cl->c.f = fn; L->top -= n; while (n--) - setobj2n(&cl->c.upvalue[n], L->top+n); - setclvalue(L->top, cl); + setobj2n(L, &cl->c.upvalue[n], L->top+n); + setclvalue(L, L->top, cl); + lua_assert(iswhite(obj2gco(cl))); api_incr_top(L); lua_unlock(L); } @@ -485,7 +495,21 @@ LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = luaA_index(L, idx); - setobj2s(L->top - 1, luaV_gettable(L, t, L->top - 1, 0)); + api_checkvalidindex(L, t); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); +} + + +LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + t = luaA_index(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_gettable(L, t, &key, L->top); + api_incr_top(L); lua_unlock(L); } @@ -495,7 +519,7 @@ LUA_API void lua_rawget (lua_State *L, int idx) { lua_lock(L); t = luaA_index(L, idx); api_check(L, ttistable(t)); - setobj2s(L->top - 1, luaH_get(hvalue(t), L->top - 1)); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } @@ -505,41 +529,39 @@ LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { lua_lock(L); o = luaA_index(L, idx); api_check(L, ttistable(o)); - setobj2s(L->top, luaH_getnum(hvalue(o), n)); + setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } -LUA_API void lua_newtable (lua_State *L) { +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { lua_lock(L); luaC_checkGC(L); - sethvalue(L->top, luaH_new(L, 0, 0)); + sethvalue(L, L->top, luaH_new(L, narray, luaO_log2(nrec) + 1)); api_incr_top(L); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TObject *obj; + const TValue *obj; Table *mt = NULL; int res; lua_lock(L); - obj = luaA_indexAcceptable(L, objindex); - if (obj != NULL) { - switch (ttype(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->uv.metatable; - break; - } + obj = luaA_index(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; } - if (mt == NULL || mt == hvalue(defaultmeta(L))) + if (mt == NULL) res = 0; else { - sethvalue(L->top, mt); + sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } @@ -552,7 +574,8 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = luaA_index(L, idx); - setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); + api_checkvalidindex(L, o); + setobj2s(L, L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); api_incr_top(L); lua_unlock(L); } @@ -568,19 +591,35 @@ LUA_API void lua_settable (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 2); t = luaA_index(L, idx); + api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + api_checknelems(L, 1); + t = luaA_index(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_settable(L, t, &key, L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); +} + + LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = luaA_index(L, idx); api_check(L, ttistable(t)); - setobj2t(luaH_set(L, hvalue(t), L->top-2), L->top-1); /* write barrier */ + setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + luaC_barrier(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } @@ -592,27 +631,38 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { api_checknelems(L, 1); o = luaA_index(L, idx); api_check(L, ttistable(o)); - setobj2t(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */ + setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + luaC_barrier(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TObject *obj, *mt; + TValue *obj; + Table *mt; int res = 1; lua_lock(L); api_checknelems(L, 1); obj = luaA_index(L, objindex); - mt = (!ttisnil(L->top - 1)) ? L->top - 1 : defaultmeta(L); - api_check(L, ttistable(mt)); + api_checkvalidindex(L, obj); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1)); + mt = hvalue(L->top - 1); + } switch (ttype(obj)) { case LUA_TTABLE: { - hvalue(obj)->metatable = hvalue(mt); /* write barrier */ + hvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { - uvalue(obj)->uv.metatable = hvalue(mt); /* write barrier */ + uvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, rawuvalue(obj), mt); break; } default: { @@ -632,6 +682,7 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); o = luaA_index(L, idx); + api_checkvalidindex(L, o); L->top--; api_check(L, ttistable(L->top)); if (isLfunction(o)) { @@ -679,7 +730,13 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { int status; ptrdiff_t func; lua_lock(L); - func = (errfunc == 0) ? 0 : savestack(L, luaA_index(L, errfunc)); + if (errfunc == 0) + func = 0; + else { + StkId o = luaA_index(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); @@ -702,7 +759,7 @@ static void f_Ccall (lua_State *L, void *ud) { Closure *cl; cl = luaF_newCclosure(L, 0); cl->c.f = c->func; - setclvalue(L->top, cl); /* push function */ + setclvalue(L, L->top, cl); /* push function */ incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ incr_top(L); @@ -726,12 +783,10 @@ LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, const char *chunkname) { ZIO z; int status; - int c; lua_lock(L); if (!chunkname) chunkname = "?"; - luaZ_init(&z, reader, data, chunkname); - c = luaZ_lookahead(&z); - status = luaD_protectedparser(L, &z, (c == LUA_SIGNATURE[0])); + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname); lua_unlock(L); return status; } @@ -739,14 +794,12 @@ LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { int status; - TObject *o; + TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; - if (isLfunction(o) && clvalue(o)->l.nupvalues == 0) { - luaU_dump(L, clvalue(o)->l.p, writer, data); - status = 1; - } + if (isLfunction(o)) + status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); else status = 0; lua_unlock(L); @@ -755,39 +808,34 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { /* -** Garbage-collection functions +** Garbage-collection function */ -/* GC values are expressed in Kbytes: #bytes/2^10 */ -#define GCscalel(x) ((x)>>10) -#define GCscale(x) (cast(int, GCscalel(x))) -#define GCunscale(x) (cast(lu_mem, x)<<10) - -LUA_API int lua_getgcthreshold (lua_State *L) { - int threshold; - lua_lock(L); - threshold = GCscale(G(L)->GCthreshold); - lua_unlock(L); - return threshold; +LUA_API int lua_gc (lua_State *L, int what, int data) { + global_State *g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAXLMEM; + return 0; + } + case LUA_GCRESTART: { + g->GCthreshold = g->nblocks; + return 0; + } + case LUA_GCCOLLECT: { + lua_lock(L); + luaC_fullgc(L); + lua_unlock(L); + return 0; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + return cast(int, g->nblocks >> 10); + } + default: return -1; /* invalid option */ + } } -LUA_API int lua_getgccount (lua_State *L) { - int count; - lua_lock(L); - count = GCscale(G(L)->nblocks); - lua_unlock(L); - return count; -} - -LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { - lua_lock(L); - if (cast(lu_mem, newthreshold) > GCscalel(MAX_LUMEM)) - G(L)->GCthreshold = MAX_LUMEM; - else - G(L)->GCthreshold = GCunscale(newthreshold); - luaC_checkGC(L); - lua_unlock(L); -} /* @@ -835,7 +883,7 @@ LUA_API void lua_concat (lua_State *L, int n) { L->top -= (n-1); } else if (n == 0) { /* push empty string */ - setsvalue2s(L->top, luaS_newlstr(L, NULL, 0)); + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ @@ -843,39 +891,28 @@ LUA_API void lua_concat (lua_State *L, int n) { } +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + *ud = G(L)->ud; + return G(L)->realloc; +} + + LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); u = luaS_newudata(L, size); - setuvalue(L->top, u); + setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return u + 1; } -LUA_API int lua_pushupvalues (lua_State *L) { - Closure *func; - int n, i; - lua_lock(L); - api_check(L, iscfunction(L->base - 1)); - func = clvalue(L->base - 1); - n = func->c.nupvalues; - luaD_checkstack(L, n + LUA_MINSTACK); - for (i=0; i<n; i++) { - setobj2s(L->top, &func->c.upvalue[i]); - L->top++; - } - lua_unlock(L); - return n; -} -static const char *aux_upvalue (lua_State *L, int funcindex, int n, - TObject **val) { +static const char *aux_upvalue (lua_State *L, StkId fi, int n, TValue **val) { Closure *f; - StkId fi = luaA_index(L, funcindex); if (!ttisfunction(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { @@ -894,11 +931,11 @@ static const char *aux_upvalue (lua_State *L, int funcindex, int n, LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; - TObject *val; + TValue *val; lua_lock(L); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(L, luaA_index(L, funcindex), n, &val); if (name) { - setobj2s(L->top, val); + setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); @@ -908,13 +945,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; - TObject *val; + TValue *val; + StkId fi; lua_lock(L); + fi = luaA_index(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(L, fi, n, &val); if (name) { L->top--; - setobj(val, L->top); /* write barrier */ + setobj(L, val, L->top); + luaC_barrier(L, clvalue(fi), L->top); } lua_unlock(L); return name; @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 1.21 2002/03/04 21:29:41 roberto Exp $ +** $Id: lapi.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -11,6 +11,6 @@ #include "lobject.h" -void luaA_pushobject (lua_State *L, const TObject *o); +void luaA_pushobject (lua_State *L, const TValue *o); #endif diff --git a/src/lcode.c b/src/lcode.c index d626ecd6..de6939bb 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.117 2003/04/03 13:35:34 roberto Exp $ +** $Id: lcode.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "lcode.h" #include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" @@ -88,7 +89,7 @@ static int luaK_getjump (FuncState *fs, int pc) { static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT)) + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; @@ -206,41 +207,46 @@ static void freeexp (FuncState *fs, expdesc *e) { } -static int addk (FuncState *fs, TObject *k, TObject *v) { - const TObject *idx = luaH_get(fs->h, k); +static int addk (FuncState *fs, TValue *k, TValue *v) { + lua_State *L = fs->L; + TValue *idx = luaH_set(L, fs->h, k); + Proto *f = fs->f; + int oldsize = f->sizek; if (ttisnumber(idx)) { lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v)); return cast(int, nvalue(idx)); } else { /* constant not found; create a new entry */ - Proto *f = fs->f; - luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject, + setnvalue(idx, cast(lua_Number, fs->nk)); + luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, MAXARG_Bx, "constant table overflow"); - setobj2n(&f->k[fs->nk], v); - setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk)); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[fs->nk], v); + luaC_barrier(L, f, v); return fs->nk++; } } int luaK_stringK (FuncState *fs, TString *s) { - TObject o; - setsvalue(&o, s); + TValue o; + setsvalue(fs->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { - TObject o; + TValue o; setnvalue(&o, r); return addk(fs, &o, &o); } static int nil_constant (FuncState *fs) { - TObject k, v; + TValue k, v; setnilvalue(&v); - sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */ + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->L, &k, fs->h); return addk(fs, &k, &v); } @@ -416,25 +422,25 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { } -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { - freeexp(fs, exp); - luaK_exp2reg(fs, exp, var->info); + freeexp(fs, ex); + luaK_exp2reg(fs, ex, var->info); return; } case VUPVAL: { - int e = luaK_exp2anyreg(fs, exp); + int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); break; } case VGLOBAL: { - int e = luaK_exp2anyreg(fs, exp); + int e = luaK_exp2anyreg(fs, ex); luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); break; } case VINDEXED: { - int e = luaK_exp2RK(fs, exp); + int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); break; } @@ -443,7 +449,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { break; } } - freeexp(fs, exp); + freeexp(fs, ex); } @@ -462,8 +468,7 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->info); - lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) && - GET_OPCODE(*pc) != OP_TEST); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } @@ -703,12 +708,15 @@ int luaK_code (FuncState *fs, Instruction i, int line) { int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); } diff --git a/src/ldebug.c b/src/ldebug.c index 8e511e3b..42080ccd 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,13 +1,15 @@ /* -** $Id: ldebug.c,v 1.150 2003/03/19 21:24:04 roberto Exp $ +** $Id: ldebug.c,v 2.3 2004/03/23 13:10:16 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stdarg.h> +#include <stddef.h> #include <string.h> + #define ldebug_c #include "lua.h" @@ -30,14 +32,8 @@ static const char *getfuncname (CallInfo *ci, const char **name); -#define isLua(ci) (!((ci)->state & CI_C)) - - static int currentpc (CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci->state & CI_HASFRAME) /* function has a frame? */ - ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */ - /* function's pc is saved */ return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); } @@ -51,14 +47,6 @@ static int currentline (CallInfo *ci) { } -void luaG_inithooks (lua_State *L) { - CallInfo *ci; - for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */ - currentpc(ci); - L->hookinit = 1; -} - - /* ** this function can be called asynchronous (e.g. during a signal) */ @@ -71,7 +59,6 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { L->basehookcount = count; resethookcount(L); L->hookmask = cast(lu_byte, mask); - L->hookinit = 0; return 1; } @@ -97,7 +84,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { lua_lock(L); for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { level--; - if (!(ci->state & CI_C)) /* Lua function? */ + if (f_isLua(ci)) /* Lua function? */ level -= ci->u.l.tailcalls; /* skip lost tail calls */ } if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ @@ -151,7 +138,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { if (!name || name[0] == '(') /* `(' starts private locals */ name = NULL; else - setobjs2s(ci->base+(n-1), L->top); + setobjs2s(L, ci->base+(n-1), L->top); } lua_unlock(L); return name; @@ -174,18 +161,6 @@ static void funcinfo (lua_Debug *ar, StkId func) { } -static const char *travglobals (lua_State *L, const TObject *o) { - Table *g = hvalue(gt(L)); - int i = sizenode(g); - while (i--) { - Node *n = gnode(g, i); - if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n))) - return getstr(tsvalue(gkey(n))); - } - return NULL; -} - - static void info_tailcall (lua_State *L, lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; @@ -217,15 +192,13 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, case 'n': { ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; if (ar->namewhat == NULL) { - /* try to find a global name */ - if ((ar->name = travglobals(L, f)) != NULL) - ar->namewhat = "global"; - else ar->namewhat = ""; /* not found */ + ar->namewhat = ""; /* not found */ + ar->name = NULL; } break; } case 'f': { - setobj2s(L->top, f); + setobj2s(L, L->top, f); break; } default: status = 0; /* invalid option */ @@ -296,8 +269,16 @@ static int checkopenop (const Proto *pt, int pc) { } -static int checkRK (const Proto *pt, int r) { - return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); +static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { + switch (mode) { + case OpArgN: check(r == 0); break; + case OpArgU: break; + case OpArgR: checkreg(pt, r); break; + case OpArgK: + check(r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); + break; + } + return 1; } @@ -312,34 +293,34 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int a = GETARG_A(i); int b = 0; int c = 0; + check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); - if (testOpMode(op, OpModeBreg)) { - checkreg(pt, b); - } - else if (testOpMode(op, OpModeBrk)) - check(checkRK(pt, b)); - if (testOpMode(op, OpModeCrk)) - check(checkRK(pt, c)); + check(checkArgMode(pt, b, getBMode(op))); + check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); - if (testOpMode(op, OpModeK)) check(b < pt->sizek); + if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); + if (getBMode(op) == OpArgR) { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + } break; } } - if (testOpMode(op, OpModesetA)) { + if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } - if (testOpMode(op, OpModeT)) { + if (testTMode(op)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } @@ -369,20 +350,21 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_CONCAT: { - /* `c' is a register, and at least two operands */ - check(c < MAXSTACK && b < c); + check(b < c); /* at least two operands */ break; } - case OP_TFORLOOP: - checkreg(pt, a+c+5); + case OP_TFORLOOP: { + checkreg(pt, a+5); /* space for control variables */ if (reg >= a) last = pc; /* affect all registers above base */ - /* go through */ + break; + } + case OP_TFORPREP: case OP_FORLOOP: - checkreg(pt, a+2); + case OP_FORPREP: + checkreg(pt, a+3); /* go through */ case OP_JMP: { int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ @@ -436,7 +418,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int luaG_checkcode (const Proto *pt) { - return luaG_symbexec(pt, pt->sizecode, NO_REG); + return (luaG_symbexec(pt, pt->sizecode, NO_REG) != 0); } @@ -478,6 +460,11 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { *name = kname(p, k); return "field"; } + case OP_GETUPVAL: { + int u = GETARG_B(i); /* upvalue index */ + *name = getstr(p->upvalues[u]); + return "upvalue"; + } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); @@ -504,7 +491,7 @@ static const char *getfuncname (CallInfo *ci, const char **name) { /* only ANSI way to check whether a pointer points to an array */ -static int isinstack (CallInfo *ci, const TObject *o) { +static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->base; p < ci->top; p++) if (o == p) return 1; @@ -512,7 +499,7 @@ static int isinstack (CallInfo *ci, const TObject *o) { } -void luaG_typeerror (lua_State *L, const TObject *o, const char *op) { +void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? @@ -532,15 +519,15 @@ void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { } -void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) { - TObject temp; +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { + TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ luaG_typeerror(L, p2, "perform arithmetic on"); } -int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) { +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = luaT_typenames[ttype(p1)]; const char *t2 = luaT_typenames[ttype(p2)]; if (t1[2] == t2[2]) @@ -566,8 +553,8 @@ void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); - setobjs2s(L->top, L->top - 1); /* move argument */ - setobjs2s(L->top - 1, errfunc); /* push function */ + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } diff --git a/src/ldebug.h b/src/ldebug.h index 7ff39583..d7163f2d 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 1.32 2002/11/18 11:01:55 roberto Exp $ +** $Id: ldebug.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -18,11 +18,10 @@ #define resethookcount(L) (L->hookcount = L->basehookcount) -void luaG_inithooks (lua_State *L); -void luaG_typeerror (lua_State *L, const TObject *o, const char *opname); +void luaG_typeerror (lua_State *L, const TValue *o, const char *opname); void luaG_concaterror (lua_State *L, StkId p1, StkId p2); -void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2); -int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2); +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2); +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); void luaG_runerror (lua_State *L, const char *fmt, ...); void luaG_errormsg (lua_State *L); int luaG_checkcode (const Proto *pt); @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.217a 2003/04/03 13:35:34 roberto Exp $ +** $Id: ldo.c,v 2.2 2004/03/23 17:02:58 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -39,6 +39,20 @@ */ +#ifndef LUA_USEEXCEPTIONS + +#define L_THROW(c) longjmp((c)->b, 1) +#define L_TRY(c,a) if (setjmp((c)->b) == 0) { a } + +#else + +#define L_THROW(c) throw(c) +#define L_TRY(c,a) try { a } catch(...) \ + { if ((c)->status == 0) (c)->status = -1; } + +#endif + + /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; @@ -50,16 +64,16 @@ struct lua_longjmp { static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { - setsvalue2s(oldtop, luaS_new(L, MEMERRMSG)); + setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); break; } case LUA_ERRERR: { - setsvalue2s(oldtop, luaS_new(L, "error in error handling")); + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } case LUA_ERRSYNTAX: case LUA_ERRRUN: { - setobjs2s(oldtop, L->top - 1); /* error message on current top */ + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } @@ -70,10 +84,10 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; - longjmp(L->errorJmp->b, 1); + L_THROW(L->errorJmp); } else { - G(L)->panic(L); + if (G(L)->panic) G(L)->panic(L); exit(EXIT_FAILURE); } } @@ -84,8 +98,9 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; - if (setjmp(lj.b) == 0) + L_TRY(&lj, (*f)(L, ud); + ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } @@ -103,12 +118,12 @@ static void restore_stack_limit (lua_State *L) { /* }====================================================== */ -static void correctstack (lua_State *L, TObject *oldstack) { +static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; GCObject *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) - gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack; + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; for (ci = L->base_ci; ci <= L->ci; ci++) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; @@ -118,8 +133,8 @@ static void correctstack (lua_State *L, TObject *oldstack) { void luaD_reallocstack (lua_State *L, int newsize) { - TObject *oldstack = L->stack; - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject); + TValue *oldstack = L->stack; + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); L->stacksize = newsize; L->stack_last = L->stack+newsize-1-EXTRA_STACK; correctstack(L, oldstack); @@ -183,7 +198,6 @@ void luaD_callhook (lua_State *L, int event, int line) { static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { int i; Table *htab; - TObject nname; int actual = L->top - base; /* actual number of arguments */ if (actual < nfixargs) { luaD_checkstack(L, nfixargs - actual); @@ -193,27 +207,28 @@ static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { actual -= nfixargs; /* number of extra arguments */ htab = luaH_new(L, actual, 1); /* create `arg' table */ for (i=0; i<actual; i++) /* put extra arguments into `arg' table */ - setobj2n(luaH_setnum(L, htab, i+1), L->top - actual + i); + setobj2n(L, luaH_setnum(L, htab, i+1), L->top - actual + i); /* store counter in field `n' */ - setsvalue(&nname, luaS_newliteral(L, "n")); - setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual)); + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), + cast(lua_Number, actual)); L->top -= actual; /* remove extra elements from the stack */ - sethvalue(L->top, htab); + sethvalue(L, L->top, htab); + lua_assert(iswhite(obj2gco(htab))); incr_top(L); } static StkId tryfuncTM (lua_State *L, StkId func) { - const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ - for (p = L->top; p > func; p--) setobjs2s(p, p-1); + for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); incr_top(L); func = restorestack(L, funcr); /* previous call may change stack */ - setobj2s(func, tm); /* tag method is the new function to be called */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ return func; } @@ -228,6 +243,7 @@ StkId luaD_precall (lua_State *L, StkId func) { cl = &clvalue(func)->l; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; + StkId st; Proto *p = cl->p; if (p->is_vararg) /* varargs? */ adjust_varargs(L, p->numparams, func+1); @@ -237,9 +253,8 @@ StkId luaD_precall (lua_State *L, StkId func) { ci->top = L->base + p->maxstacksize; ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.tailcalls = 0; - ci->state = CI_SAVEDPC; - while (L->top < ci->top) - setnilvalue(L->top++); + for (st = L->top; st < ci->top; st++) + setnilvalue(st); L->top = ci->top; return NULL; } @@ -250,14 +265,10 @@ StkId luaD_precall (lua_State *L, StkId func) { ci = ++L->ci; /* now `enter' new function */ L->base = L->ci->base = restorestack(L, funcr) + 1; ci->top = L->top + LUA_MINSTACK; - ci->state = CI_C; /* a C function */ if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); -#ifdef LUA_COMPATUPVALUES - lua_pushupvalues(L); -#endif - n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */ + n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); return L->top - n; } @@ -267,7 +278,7 @@ StkId luaD_precall (lua_State *L, StkId func) { static StkId callrethooks (lua_State *L, StkId firstResult) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ luaD_callhook(L, LUA_HOOKRET, -1); - if (!(L->ci->state & CI_C)) { /* Lua function? */ + if (f_isLua(L->ci)) { /* Lua function? */ while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } @@ -284,7 +295,7 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { L->base = L->ci->base; /* restore base */ /* move results to correct place */ while (wanted != 0 && firstResult < L->top) { - setobjs2s(res++, firstResult++); + setobjs2s(L, res++, firstResult++); wanted--; } while (wanted-- > 0) @@ -301,7 +312,6 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { */ void luaD_call (lua_State *L, StkId func, int nResults) { StkId firstResult; - lua_assert(!(L->ci->state & CI_CALLING)); if (++L->nCcalls >= LUA_MAXCCALLS) { if (L->nCcalls == LUA_MAXCCALLS) luaG_runerror(L, "C stack overflow"); @@ -310,7 +320,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { } firstResult = luaD_precall(L, func); if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L); /* call it */ + firstResult = luaV_execute(L, 1); /* call it */ luaD_poscall(L, nResults, firstResult); L->nCcalls--; luaC_checkGC(L); @@ -321,27 +331,23 @@ static void resume (lua_State *L, void *ud) { StkId firstResult; int nargs = *cast(int *, ud); CallInfo *ci = L->ci; - if (ci == L->base_ci) { /* no activation record? */ - lua_assert(nargs < L->top - L->base); + if (!L->isSuspended) { + lua_assert(ci == L->base_ci && nargs < L->top - L->base); luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ } - else { /* inside a yield */ - lua_assert(ci->state & CI_YIELD); - if (ci->state & CI_C) { /* `common' yield? */ + else { /* resuming from previous yield */ + if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ int nresults; - lua_assert((ci-1)->state & CI_SAVEDPC); lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, L->top - nargs); /* complete it */ if (nresults >= 0) L->top = L->ci->top; - } - else { /* yielded inside a hook: just continue its execution */ - ci->state &= ~CI_YIELD; - } + } /* else yielded inside a hook: just continue its execution */ } - firstResult = luaV_execute(L); + L->isSuspended = 0; + firstResult = luaV_execute(L, L->ci - L->base_ci); if (firstResult != NULL) /* return? */ luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ } @@ -349,7 +355,7 @@ static void resume (lua_State *L, void *ud) { static int resume_error (lua_State *L, const char *msg) { L->top = L->ci->base; - setsvalue2s(L->top, luaS_new(L, msg)); + setsvalue2s(L, L->top, luaS_new(L, msg)); incr_top(L); lua_unlock(L); return LUA_ERRRUN; @@ -360,14 +366,16 @@ LUA_API int lua_resume (lua_State *L, int nargs) { int status; lu_byte old_allowhooks; lua_lock(L); - if (L->ci == L->base_ci) { - if (nargs >= L->top - L->base) - return resume_error(L, "cannot resume dead coroutine"); + lua_assert(L->errfunc == 0 && L->nCcalls == 0); + if (!L->isSuspended) { + if (L->ci == L->base_ci) { /* no activation record? */ + if (nargs >= L->top - L->base) + return resume_error(L, "cannot resume dead coroutine"); + } + else + return resume_error(L, "cannot resume non-suspended coroutine"); } - else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ - return resume_error(L, "cannot resume non-suspended coroutine"); old_allowhooks = L->allowhook; - lua_assert(L->errfunc == 0 && L->nCcalls == 0); status = luaD_rawrunprotected(L, resume, &nargs); if (status != 0) { /* error? */ L->ci = L->base_ci; /* go back to initial level */ @@ -389,17 +397,15 @@ LUA_API int lua_yield (lua_State *L, int nresults) { ci = L->ci; if (L->nCcalls > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - if (ci->state & CI_C) { /* usual yield */ - if ((ci-1)->state & CI_C) - luaG_runerror(L, "cannot yield a C function"); + if (!f_isLua(ci)) { /* usual yield */ if (L->top - nresults > L->base) { /* is there garbage in the stack? */ int i; for (i=0; i<nresults; i++) /* move down results */ - setobjs2s(L->base + i, L->top - nresults + i); + setobjs2s(L, L->base + i, L->top - nresults + i); L->top = L->base + nresults; } } /* else it's an yield inside a hook: nothing to do */ - ci->state |= CI_YIELD; + L->isSuspended = 1; lua_unlock(L); return -1; } @@ -436,35 +442,34 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ - int bin; + const char *name; }; static void f_parser (lua_State *L, void *ud) { - struct SParser *p; + int i; Proto *tf; Closure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = luaZ_lookahead(p->z); luaC_checkGC(L); - p = cast(struct SParser *, ud); - tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff); - cl = luaF_newLclosure(L, 0, gt(L)); + tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, + &p->buff, p->name); + cl = luaF_newLclosure(L, tf->nups, gt(L)); cl->l.p = tf; - setclvalue(L->top, cl); + for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + cl->l.upvals[i] = luaF_newupval(L); + setclvalue(L, L->top, cl); incr_top(L); } -int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; - ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */ - p.z = z; p.bin = bin; + p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); - status = luaD_rawrunprotected(L, f_parser, &p); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); - if (status != 0) { /* error? */ - StkId oldtop = restorestack(L, oldtopr); - seterrorobj(L, status, oldtop); - } return status; } @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.56 2002/12/04 17:29:32 roberto Exp $ +** $Id: ldo.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ #define luaD_checkstack(L,n) \ - if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TObject)) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ luaD_growstack(L, n); \ else condhardstacktests(luaD_reallocstack(L, L->stacksize)); @@ -32,7 +32,7 @@ #define incr_top(L) {luaD_checkstack(L,1); L->top++;} #define savestack(L,p) ((char *)(p) - (char *)L->stack) -#define restorestack(L,n) ((TObject *)((char *)L->stack + (n))) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) #define saveci(L,p) ((char *)(p) - (char *)L->base_ci) #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) @@ -42,7 +42,7 @@ typedef void (*Pfunc) (lua_State *L, void *ud); void luaD_resetprotection (lua_State *L); -int luaD_protectedparser (lua_State *L, ZIO *z, int bin); +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); void luaD_callhook (lua_State *L, int event, int line); StkId luaD_precall (lua_State *L, StkId func); void luaD_call (lua_State *L, StkId func, int nResults); diff --git a/src/ldump.c b/src/ldump.c index 234b011f..dc4ebad1 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.4 2003/02/11 23:52:12 lhf Exp $ +** $Id: ldump.c,v 1.6 2004/03/24 00:25:08 lhf Exp $ ** save bytecodes ** See Copyright Notice in lua.h */ @@ -22,6 +22,7 @@ typedef struct { lua_State* L; lua_Chunkwriter write; void* data; + int strip; } DumpState; static void DumpBlock(const void* b, size_t size, DumpState* D) @@ -103,7 +104,7 @@ static void DumpConstants(const Proto* f, DumpState* D) DumpInt(n=f->sizek,D); for (i=0; i<n; i++) { - const TObject* o=&f->k[i]; + const TValue* o=&f->k[i]; DumpByte(ttype(o),D); switch (ttype(o)) { @@ -111,7 +112,7 @@ static void DumpConstants(const Proto* f, DumpState* D) DumpNumber(nvalue(o),D); break; case LUA_TSTRING: - DumpString(tsvalue(o),D); + DumpString(rawtsvalue(o),D); break; case LUA_TNIL: break; @@ -132,9 +133,9 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpByte(f->numparams,D); DumpByte(f->is_vararg,D); DumpByte(f->maxstacksize,D); - DumpLines(f,D); - DumpLocals(f,D); - DumpUpvalues(f,D); + if (D->strip) DumpInt(0,D); else DumpLines(f,D); + if (D->strip) DumpInt(0,D); else DumpLocals(f,D); + if (D->strip) DumpInt(0,D); else DumpUpvalues(f,D); DumpConstants(f,D); DumpCode(f,D); } @@ -147,10 +148,6 @@ static void DumpHeader(DumpState* D) DumpByte(sizeof(int),D); DumpByte(sizeof(size_t),D); DumpByte(sizeof(Instruction),D); - DumpByte(SIZE_OP,D); - DumpByte(SIZE_A,D); - DumpByte(SIZE_B,D); - DumpByte(SIZE_C,D); DumpByte(sizeof(lua_Number),D); DumpNumber(TEST_NUMBER,D); } @@ -158,13 +155,14 @@ static void DumpHeader(DumpState* D) /* ** dump function as precompiled chunk */ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data) +int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip) { DumpState D; D.L=L; D.write=w; D.data=data; + D.strip=strip; DumpHeader(&D); DumpFunction(Main,NULL,&D); + return 1; } - diff --git a/src/lfunc.c b/src/lfunc.c index 31044fa5..d9f4e27e 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,11 +1,11 @@ /* -** $Id: lfunc.c,v 1.67 2003/03/18 12:50:04 roberto Exp $ +** $Id: lfunc.c,v 2.3 2004/03/15 21:04:33 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stddef.h> #define lfunc_c @@ -18,65 +18,75 @@ #include "lstate.h" -#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ - cast(int, sizeof(TObject)*((n)-1))) - -#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ - cast(int, sizeof(TObject *)*((n)-1))) - - Closure *luaF_newCclosure (lua_State *L, int nelems) { Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; c->c.nupvalues = cast(lu_byte, nelems); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) { +Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; c->l.g = *e; c->l.nupvalues = cast(lu_byte, nelems); + while (nelems--) c->l.upvals[nelems] = NULL; return c; } +UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = luaM_new(L, UpVal); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv->v = &uv->value; + setnilvalue(uv->v); + return uv; +} + + UpVal *luaF_findupval (lua_State *L, StkId level) { GCObject **pp = &L->openupval; UpVal *p; - UpVal *v; + UpVal *uv; while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { if (p->v == level) return p; pp = &p->next; } - v = luaM_new(L, UpVal); /* not found: create a new one */ - v->tt = LUA_TUPVAL; - v->marked = 1; /* open upvalues should not be collected */ - v->v = level; /* current value lives in the stack */ - v->next = *pp; /* chain it in the proper position */ - *pp = valtogco(v); - return v; + uv = luaM_new(L, UpVal); /* not found: create a new one */ + uv->tt = LUA_TUPVAL; + uv->marked = luaC_white(G(L)); + uv->v = level; /* current value lives in the stack */ + uv->next = *pp; /* chain it in the proper position */ + *pp = obj2gco(uv); + return uv; } void luaF_close (lua_State *L, StkId level) { - UpVal *p; - while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) { - setobj(&p->value, p->v); /* save current value (write barrier) */ - p->v = &p->value; /* now current value lives here */ - L->openupval = p->next; /* remove from `open' list */ - luaC_link(L, valtogco(p), LUA_TUPVAL); + UpVal *uv; + global_State *g = G(L); + while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o)); + L->openupval = uv->next; /* remove from `open' list */ + if (isdead(g, o)) + luaM_freelem(L, uv); /* free upvalue */ + else { + setobj(L, &uv->value, uv->v); + uv->v = &uv->value; /* now current value lives here */ + luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + } } } Proto *luaF_newproto (lua_State *L) { Proto *f = luaM_new(L, Proto); - luaC_link(L, valtogco(f), LUA_TPROTO); + luaC_link(L, obj2gco(f), LUA_TPROTO); f->k = NULL; f->sizek = 0; f->p = NULL; @@ -102,7 +112,7 @@ Proto *luaF_newproto (lua_State *L) { void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->p, f->sizep, Proto *); - luaM_freearray(L, f->k, f->sizek, TObject); + luaM_freearray(L, f->k, f->sizek, TValue); luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); diff --git a/src/lfunc.h b/src/lfunc.h index 5d532507..04437601 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 1.21 2003/03/18 12:50:04 roberto Exp $ +** $Id: lfunc.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -11,9 +11,17 @@ #include "lobject.h" +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + Proto *luaF_newproto (lua_State *L); Closure *luaF_newCclosure (lua_State *L, int nelems); -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e); +Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e); +UpVal *luaF_newupval (lua_State *L); UpVal *luaF_findupval (lua_State *L, StkId level); void luaF_close (lua_State *L, StkId level); void luaF_freeproto (lua_State *L, Proto *f); @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ +** $Id: lgc.c,v 2.6 2004/03/23 12:57:12 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -22,117 +22,130 @@ #include "ltm.h" -typedef struct GCState { - GCObject *tmark; /* list of marked objects to be traversed */ - GCObject *wk; /* list of traversed key-weak tables (to be cleared) */ - GCObject *wv; /* list of traversed value-weak tables */ - GCObject *wkv; /* list of traversed key-value weak tables */ - global_State *g; -} GCState; +#define GCSTEPSIZE (40*sizeof(TValue)) +#define GCFREECOST (sizeof(TValue)/2) +#define GCSWEEPCOST sizeof(TValue) +#define GCFINALIZECOST (10*sizeof(TValue)) -/* -** some userful bit tricks -*/ -#define setbit(x,b) ((x) |= (1<<(b))) -#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) -#define testbit(x,b) ((x) & (1<<(b))) +#define FIXEDMASK bitmask(FIXEDBIT) + +#define maskmarks \ + cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) -#define unmark(x) resetbit((x)->gch.marked, 0) -#define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) +#define makewhite(g,x) \ + ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) -#define stringmark(s) setbit((s)->tsv.marked, 0) +#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define gray2black(x) setbit((x)->gch.marked, BLACKBIT) +#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) +#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) -#define isfinalized(u) (!testbit((u)->uv.marked, 1)) -#define markfinalized(u) resetbit((u)->uv.marked, 1) +#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) setbit((u)->marked, FINALIZEDBIT) -#define KEYWEAKBIT 1 -#define VALUEWEAKBIT 2 -#define KEYWEAK (1<<KEYWEAKBIT) -#define VALUEWEAK (1<<VALUEWEAKBIT) +#define KEYWEAK bitmask(KEYWEAKBIT) +#define VALUEWEAK bitmask(VALUEWEAKBIT) -#define markobject(st,o) { checkconsistency(o); \ - if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); } -#define condmarkobject(st,o,c) { checkconsistency(o); \ - if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \ - reallymarkobject(st,gcvalue(o)); } +#define markvalue(g,o) { checkconsistency(o); \ + if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } -#define markvalue(st,t) { if (!ismarked(valtogco(t))) \ - reallymarkobject(st, valtogco(t)); } +#define markobject(g,t) { if (iswhite(obj2gco(t))) \ + reallymarkobject(g, obj2gco(t)); } -static void reallymarkobject (GCState *st, GCObject *o) { - lua_assert(!ismarked(o)); - setbit(o->gch.marked, 0); /* mark object */ +static void removeentry (Node *n) { + setnilvalue(gval(n)); /* remove corresponding value ... */ + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ +} + + +static void reallymarkobject (global_State *g, GCObject *o) { + lua_assert(iswhite(o) && !isdead(g, o)); + white2gray(o); switch (o->gch.tt) { + case LUA_TSTRING: { + return; + } case LUA_TUSERDATA: { - markvalue(st, gcotou(o)->uv.metatable); - break; + Table *mt = gco2u(o)->metatable; + gray2black(o); /* udata are never gray */ + if (mt) markobject(g, mt); + return; + } + case LUA_TUPVAL: { + UpVal *uv = gco2uv(o); + if (uv->v == &uv->value) { /* closed? */ + markvalue(g, uv->v); + gray2black(o); + } + return; } case LUA_TFUNCTION: { - gcotocl(o)->c.gclist = st->tmark; - st->tmark = o; + gco2cl(o)->c.gclist = g->gray; + g->gray = o; break; } case LUA_TTABLE: { - gcotoh(o)->gclist = st->tmark; - st->tmark = o; + gco2h(o)->gclist = g->gray; + g->gray = o; break; } case LUA_TTHREAD: { - gcototh(o)->gclist = st->tmark; - st->tmark = o; + gco2th(o)->gclist = g->gray; + g->gray = o; break; } case LUA_TPROTO: { - gcotop(o)->gclist = st->tmark; - st->tmark = o; + gco2p(o)->gclist = g->gray; + g->gray = o; break; } - default: lua_assert(o->gch.tt == LUA_TSTRING); + default: lua_assert(0); } } -static void marktmu (GCState *st) { +static void marktmu (global_State *g) { GCObject *u; - for (u = st->g->tmudata; u; u = u->gch.next) { - unmark(u); /* may be marked, if left from previous GC */ - reallymarkobject(st, u); + for (u = g->tmudata; u; u = u->gch.next) { + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); } } /* move `dead' udata that need finalization to list `tmudata' */ -size_t luaC_separateudata (lua_State *L) { +size_t luaC_separateudata (lua_State *L, int all) { size_t deadmem = 0; - GCObject **p = &G(L)->rootudata; + GCObject **p = &G(L)->firstudata; GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ GCObject **lastcollected = &collected; - while ((curr = *p) != NULL) { - lua_assert(curr->gch.tt == LUA_TUSERDATA); - if (ismarked(curr) || isfinalized(gcotou(curr))) + while ((curr = *p)->gch.tt == LUA_TUSERDATA) { + if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ - - else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { - markfinalized(gcotou(curr)); /* don't need finalization */ + else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { + markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ - deadmem += sizeudata(gcotou(curr)->uv.len); + deadmem += sizeudata(gco2u(curr)->len); + markfinalized(gco2u(curr)); *p = curr->gch.next; curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; lastcollected = &curr->gch.next; } } + lua_assert(curr == obj2gco(G(L)->mainthread)); /* insert collected udata with gc event into `tmudata' list */ *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; @@ -140,89 +153,85 @@ size_t luaC_separateudata (lua_State *L) { } -static void removekey (Node *n) { - setnilvalue(gval(n)); /* remove corresponding value ... */ - if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ -} - - -static void traversetable (GCState *st, Table *h) { +static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; int weakvalue = 0; - const TObject *mode; - markvalue(st, h->metatable); - lua_assert(h->lsizenode || h->node == st->g->dummynode); - mode = gfasttm(st->g, h->metatable, TM_MODE); + const TValue *mode; + if (h->metatable) + markobject(g, h->metatable); + lua_assert(h->lsizenode || h->node == g->dummynode); + mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ - GCObject **weaklist; h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); - weaklist = (weakkey && weakvalue) ? &st->wkv : - (weakkey) ? &st->wk : - &st->wv; - h->gclist = *weaklist; /* must be cleared after GC, ... */ - *weaklist = valtogco(h); /* ... so put in the appropriate list */ + h->gclist = g->weak; /* must be cleared after GC, ... */ + g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } + if (weakkey && weakvalue) return 1; if (!weakvalue) { i = h->sizearray; while (i--) - markobject(st, &h->array[i]); + markvalue(g, &h->array[i]); } i = sizenode(h); while (i--) { Node *n = gnode(h, i); - if (!ttisnil(gval(n))) { + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { lua_assert(!ttisnil(gkey(n))); - condmarkobject(st, gkey(n), !weakkey); - condmarkobject(st, gval(n), !weakvalue); + if (!weakkey) markvalue(g, gkey(n)); + if (!weakvalue) markvalue(g, gval(n)); } } + return weakkey || weakvalue; } -static void traverseproto (GCState *st, Proto *f) { +/* +** All marks are conditional because a GC may happen while the +** prototype is still being created +*/ +static void traverseproto (global_State *g, Proto *f) { int i; - stringmark(f->source); - for (i=0; i<f->sizek; i++) { /* mark literal strings */ - if (ttisstring(f->k+i)) - stringmark(tsvalue(f->k+i)); + if (f->source) 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]) + stringmark(f->upvalues[i]); + } + for (i=0; i<f->sizep; i++) { /* mark nested protos */ + if (f->p[i]) + 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->sizeupvalues; i++) /* mark upvalue names */ - stringmark(f->upvalues[i]); - for (i=0; i<f->sizep; i++) /* mark nested protos */ - markvalue(st, f->p[i]); - for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */ - stringmark(f->locvars[i].varname); - lua_assert(luaG_checkcode(f)); } -static void traverseclosure (GCState *st, Closure *cl) { +static void traverseclosure (global_State *g, Closure *cl) { if (cl->c.isC) { int i; for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ - markobject(st, &cl->c.upvalue[i]); + markvalue(g, &cl->c.upvalue[i]); } else { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); - markvalue(st, hvalue(&cl->l.g)); - markvalue(st, cl->l.p); - for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ - UpVal *u = cl->l.upvals[i]; - if (!u->marked) { - markobject(st, &u->value); - u->marked = 1; - } - } + markobject(g, hvalue(&cl->l.g)); + markobject(g, cl->l.p); + for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->l.upvals[i]); } } @@ -239,101 +248,121 @@ static void checkstacksizes (lua_State *L, StkId max) { } -static void traversestack (GCState *st, lua_State *L1) { +static void traversestack (global_State *g, lua_State *l) { StkId o, lim; CallInfo *ci; - markobject(st, gt(L1)); - lim = L1->top; - for (ci = L1->base_ci; ci <= L1->ci; ci++) { - lua_assert(ci->top <= L1->stack_last); - lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC)); - if (lim < ci->top) - lim = ci->top; + markvalue(g, gt(l)); + lim = l->top; + for (ci = l->base_ci; ci <= l->ci; ci++) { + lua_assert(ci->top <= l->stack_last); + if (lim < ci->top) lim = ci->top; } - for (o = L1->stack; o < L1->top; o++) - markobject(st, o); + for (o = l->stack; o < l->top; o++) + markvalue(g, o); for (; o <= lim; o++) setnilvalue(o); - checkstacksizes(L1, lim); + checkstacksizes(l, lim); } -static void propagatemarks (GCState *st) { - while (st->tmark) { /* traverse marked objects */ - switch (st->tmark->gch.tt) { +/* +** traverse a given `quantity' of gray objects, +** turning them to black. Returns extra `quantity' traversed. +*/ +static l_mem propagatemarks (global_State *g, l_mem lim) { + GCObject *o; + while ((o = g->gray) != NULL) { + lua_assert(isgray(o)); + gray2black(o); + switch (o->gch.tt) { case LUA_TTABLE: { - Table *h = gcotoh(st->tmark); - st->tmark = h->gclist; - traversetable(st, h); + Table *h = gco2h(o); + g->gray = h->gclist; + if (traversetable(g, h)) /* table is weak? */ + black2gray(o); /* keep it gray */ + lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); break; } case LUA_TFUNCTION: { - Closure *cl = gcotocl(st->tmark); - st->tmark = cl->c.gclist; - traverseclosure(st, cl); + Closure *cl = gco2cl(o); + g->gray = cl->c.gclist; + traverseclosure(g, cl); + lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : + sizeLclosure(cl->l.nupvalues); break; } case LUA_TTHREAD: { - lua_State *th = gcototh(st->tmark); - st->tmark = th->gclist; - traversestack(st, th); + lua_State *th = gco2th(o); + g->gray = th->gclist; + th->gclist = g->grayagain; + g->grayagain = o; + black2gray(o); + traversestack(g, th); + lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->size_ci; break; } case LUA_TPROTO: { - Proto *p = gcotop(st->tmark); - st->tmark = p->gclist; - traverseproto(st, p); + Proto *p = gco2p(o); + g->gray = p->gclist; + traverseproto(g, p); + lim -= 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; break; } default: lua_assert(0); } + if (lim <= 0) return lim; } -} - - -static int valismarked (const TObject *o) { - if (ttisstring(o)) - stringmark(tsvalue(o)); /* strings are `values', so are never weak */ - return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); + return lim; } /* -** clear collected keys from weaktables +** The next function 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 userdata +** being finalized, keep them in keys, but not in values */ -static void cleartablekeys (GCObject *l) { - while (l) { - Table *h = gcotoh(l); - int i = sizenode(h); - lua_assert(h->marked & KEYWEAK); - while (i--) { - Node *n = gnode(h, i); - if (!valismarked(gkey(n))) /* key was collected? */ - removekey(n); /* remove entry from table */ - } - l = h->gclist; +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); } /* -** clear collected values from weaktables +** clear collected entries from weaktables */ -static void cleartablevalues (GCObject *l) { +static void cleartable (GCObject *l) { while (l) { - Table *h = gcotoh(l); + Table *h = gco2h(l); int i = h->sizearray; - lua_assert(h->marked & VALUEWEAK); - while (i--) { - TObject *o = &h->array[i]; - if (!valismarked(o)) /* value was collected? */ - setnilvalue(o); /* remove value */ + lua_assert(testbit(h->marked, VALUEWEAKBIT) || + testbit(h->marked, KEYWEAKBIT)); + if (testbit(h->marked, VALUEWEAKBIT)) { + while (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); - if (!valismarked(gval(n))) /* value was collected? */ - removekey(n); /* remove entry from table */ + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) + removeentry(n); /* remove entry from table */ } l = h->gclist; } @@ -342,21 +371,21 @@ static void cleartablevalues (GCObject *l) { static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { - case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break; - case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break; - case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break; - case LUA_TTABLE: luaH_free(L, gcotoh(o)); break; + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TUPVAL: luaM_freelem(L, gco2uv(o)); break; + case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { - lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread); - luaE_freethread(L, gcototh(o)); + lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); + luaE_freethread(L, gco2th(o)); break; } case LUA_TSTRING: { - luaM_free(L, o, sizestring(gcotots(o)->tsv.len)); + luaM_free(L, o, sizestring(gco2ts(o)->len)); break; } case LUA_TUSERDATA: { - luaM_free(L, o, sizeudata(gcotou(o)->uv.len)); + luaM_free(L, o, sizeudata(gco2u(o)->len)); break; } default: lua_assert(0); @@ -364,135 +393,283 @@ static void freeobj (lua_State *L, GCObject *o) { } -static int sweeplist (lua_State *L, GCObject **p, int limit) { +static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, + lu_int32 *count); + + +static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, + l_mem *plim, lu_int32 *count) { GCObject *curr; - int count = 0; /* number of collected items */ + global_State *g = G(L); + l_mem lim = *plim; + int deadmask = otherwhite(g); + if (keepfixed) deadmask |= FIXEDMASK; while ((curr = *p) != NULL) { - if (curr->gch.marked > limit) { - unmark(curr); + if (((curr->gch.marked ^ FIXEDMASK) & deadmask) != deadmask) { + makewhite(g, curr); + if (curr->gch.tt == LUA_TTHREAD) + lim -= sweepwholelist(L, &gco2th(curr)->openupval, keepfixed, count); p = &curr->gch.next; + lim -= GCSWEEPCOST; } else { - count++; + lua_assert(iswhite(curr)); *p = curr->gch.next; + if (curr == g->rootgc) /* is the first element of the list? */ + g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); + lim -= GCFREECOST; + if (count) (*count)--; } + if (lim <= 0) break; } - return count; + *plim = lim; + return p; } -static void sweepstrings (lua_State *L, int all) { +static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, + lu_int32 *count) { + l_mem lim = MAXLMEM; + /* empty lists are quite common here, so avoid useless calls */ + if (*p) sweeplist(L, p, keepfixed, &lim, count); + return MAXLMEM - lim; +} + + +static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { int i; - for (i=0; i<G(L)->strt.size; i++) { /* for each list */ - G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); + global_State *g = G(L); + for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ + lim -= sweepwholelist(L, &G(L)->strt.hash[i], keepfixed, &g->strt.nuse); + if (lim <= 0) break; } + g->sweepstrgc = i+1; + return lim; } -static void checkSizes (lua_State *L, size_t deadmem) { +static void checkSizes (lua_State *L) { + global_State *g = G(L); /* check size of string hash */ - if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && - G(L)->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, G(L)->strt.size/2); /* table is too big */ + if (g->strt.nuse < cast(lu_int32, G(L)->strt.size/4) && + g->strt.size > MINSTRTABSIZE*2) + luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ - if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; - luaZ_resizebuffer(L, &G(L)->buff, newsize); + if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + size_t newsize = luaZ_sizebuffer(&g->buff) / 2; + luaZ_resizebuffer(L, &g->buff, newsize); } - G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ } -static void do1gcTM (lua_State *L, Udata *udata) { - const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); +static void GCTM (lua_State *L) { + global_State *g = G(L); + GCObject *o = g->tmudata; + Udata *udata = rawgco2u(o); + const TValue *tm; + g->tmudata = udata->uv.next; /* remove udata from `tmudata' */ + udata->uv.next = g->firstudata->uv.next; /* return it to `root' list */ + g->firstudata->uv.next = o; + makewhite(g, o); + tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { - setobj2s(L->top, tm); - setuvalue(L->top+1, udata); + lu_byte oldah = L->allowhook; + L->allowhook = 0; /* stop debug hooks during GC tag method */ + setobj2s(L, L->top, tm); + setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); + L->allowhook = oldah; /* restore hooks */ } } +/* +** Call all GC tag methods +*/ void luaC_callGCTM (lua_State *L) { - lu_byte oldah = L->allowhook; - L->allowhook = 0; /* stop debug hooks during GC tag methods */ - L->top++; /* reserve space to keep udata while runs its gc method */ - while (G(L)->tmudata != NULL) { - GCObject *o = G(L)->tmudata; - Udata *udata = gcotou(o); - G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ - udata->uv.next = G(L)->rootudata; /* return it to `root' list */ - G(L)->rootudata = o; - setuvalue(L->top - 1, udata); /* keep a reference to it */ - unmark(o); - markfinalized(udata); - do1gcTM(L, udata); - } - L->top--; - L->allowhook = oldah; /* restore hooks */ + while (G(L)->tmudata) + GCTM(L); } -void luaC_sweep (lua_State *L, int all) { - if (all) all = 256; /* larger than any mark */ - sweeplist(L, &G(L)->rootudata, all); - sweepstrings(L, all); - sweeplist(L, &G(L)->rootgc, all); +void luaC_sweepall (lua_State *L) { + global_State *g = G(L); + l_mem dummy = MAXLMEM; + /* finish (occasional) current sweep */ + sweepstrings(L, 0, MAXLMEM); + sweeplist(L, &g->rootgc, 0, &dummy, NULL); + /* do a whole new sweep */ + markobject(g, g->mainthread); /* cannot collect main thread */ + g->currentwhite = otherwhite(g); + g->sweepgc = &g->rootgc; + g->sweepstrgc = 0; + sweepstrings(L, 0, MAXLMEM); + sweeplist(L, &g->rootgc, 0, &dummy, NULL); } /* mark root set */ -static void markroot (GCState *st, lua_State *L) { - global_State *g = st->g; - markobject(st, defaultmeta(L)); - markobject(st, registry(L)); - traversestack(st, g->mainthread); - if (L != g->mainthread) /* another thread is running? */ - markvalue(st, L); /* cannot collect it */ +static void markroot (lua_State *L) { + global_State *g = G(L); + lua_assert(g->gray == NULL); + g->grayagain = NULL; + g->weak = NULL; + markobject(g, g->mainthread); + /* make global table be traversed before main stack */ + markvalue(g, gt(g->mainthread)); + markvalue(g, registry(L)); + g->gcstate = GCSpropagate; } -static size_t mark (lua_State *L) { - size_t deadmem; - GCState st; - GCObject *wkv; - st.g = G(L); - st.tmark = NULL; - st.wkv = st.wk = st.wv = NULL; - markroot(&st, L); - propagatemarks(&st); /* mark all reachable objects */ - cleartablevalues(st.wkv); - cleartablevalues(st.wv); - wkv = st.wkv; /* keys must be cleared after preserving udata */ - st.wkv = NULL; - st.wv = NULL; - deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ - marktmu(&st); /* mark `preserved' userdata */ - propagatemarks(&st); /* remark, to propagate `preserveness' */ - cleartablekeys(wkv); - /* `propagatemarks' may resuscitate some weak tables; clear them too */ - cleartablekeys(st.wk); - cleartablevalues(st.wv); - cleartablekeys(st.wkv); - cleartablevalues(st.wkv); - return deadmem; +static void remarkupvals (global_State *g) { + GCObject *o; + for (o = obj2gco(g->mainthread); o; o = o->gch.next) { + if (iswhite(o)) { + GCObject *curr; + for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { + if (isgray(curr)) + markvalue(g, gco2uv(curr)->v); + } + } + } +} + + +static void atomic (lua_State *L) { + global_State *g = G(L); + lua_assert(g->gray == NULL); + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* remark weak tables */ + g->gray = g->weak; + g->weak = NULL; + lua_assert(!iswhite(obj2gco(g->mainthread))); + markobject(g, L); /* mark running thread */ + propagatemarks(g, MAXLMEM); + /* remark gray again */ + g->gray = g->grayagain; + g->grayagain = NULL; + propagatemarks(g, MAXLMEM); + luaC_separateudata(L, 0); /* separate userdata to be preserved */ + marktmu(g); /* mark `preserved' userdata */ + propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ + cleartable(g->weak); /* remove collected objects from weak tables */ + /* flip current white */ + g->currentwhite = otherwhite(g); + g->gcstate = GCSsweepstring; +} + + +static l_mem singlestep (lua_State *L, l_mem lim) { + global_State *g = G(L); + switch (g->gcstate) { + case GCSpropagate: { + if (g->gray) + lim = propagatemarks(g, lim); + else { /* no more `gray' objects */ + atomic(L); /* finish mark phase */ + lim = 0; + } + break; + } + case GCSsweepstring: { + lim = sweepstrings(L, 1, lim); + if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ + g->sweepstrgc = 0; + g->gcstate = GCSsweep; /* end sweep-string phase */ + } + break; + } + case GCSsweep: { + g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim, NULL); + if (*g->sweepgc == NULL) { /* nothing more to sweep? */ + checkSizes(L); + g->sweepgc = &g->rootgc; + g->gcstate = GCSfinalize; /* end sweep phase */ + } + break; + } + case GCSfinalize: { + if (g->tmudata) { + GCTM(L); + lim -= GCFINALIZECOST; + } + else { /* no more `udata' to finalize */ + markroot(L); /* may restart collection */ + lim = 0; + } + break; + } + default: lua_assert(0); + } + return lim; +} + + +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; + do { + lim = singlestep(L, lim); + if (g->gcstate == GCSfinalize && g->tmudata == NULL) + break; /* do not start new collection */ + } while (lim > 0); + g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; + lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/2); } -void luaC_collectgarbage (lua_State *L) { - size_t deadmem = mark(L); - luaC_sweep(L, 0); - checkSizes(L, deadmem); - luaC_callGCTM(L); +void luaC_fullgc (lua_State *L) { + global_State *g = G(L); + while (g->gcstate != GCSfinalize) { + singlestep(L, MAXLMEM); + } + markroot(L); + while (g->gcstate != GCSfinalize) { + singlestep(L, MAXLMEM); + } + g->GCthreshold = g->nblocks + GCSTEPSIZE; + luaC_callGCTM(L); /* call finalizers */ +} + + +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); + if (g->gcstate != GCSpropagate) /* sweeping phases? */ + black2gray(o); /* just mark as gray to avoid other barriers */ + else /* breaking invariant! */ + reallymarkobject(g, v); /* restore it */ } void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { - o->gch.next = G(L)->rootgc; - G(L)->rootgc = o; - o->gch.marked = 0; + global_State *g = G(L); + o->gch.next = g->rootgc; + g->rootgc = o; + o->gch.marked = luaC_white(g); o->gch.tt = tt; } + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + o->gch.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); + } + } +} + @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.19a 2003/02/28 19:45:15 roberto Exp $ +** $Id: lgc.h,v 2.5 2004/03/15 21:04:33 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,15 +11,84 @@ #include "lobject.h" -#define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \ - if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); } +/* +** Possible states of the Garbage Collector +*/ +#define GCSpropagate 0 +#define GCSsweepstring 1 +#define GCSsweep 2 +#define GCSfinalize 3 + + +/* +** some userful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) +#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) +#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) +#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) + + + +/* +** Layout for bit use in `marked' field: +** bit 0 - object is gray +** bit 1 - object is black +** bit 2 - For userdata: is finalized; + for tables: has weak keys +** bit 3 - for tables: has weak values +** bit 4 - object is fixed (should not be collected) +*/ + +#define WHITE0BIT 0 +#define WHITE1BIT 1 +#define BLACKBIT 2 +#define FINALIZEDBIT 3 +#define KEYWEAKBIT 3 +#define VALUEWEAKBIT 4 +#define FIXEDBIT 5 + + +#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define isgray(x) (!isblack(x) && !iswhite(x)) + +#define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g)) + +#define changewhite(x) ((x)->gch.marked ^= bit2mask(WHITE0BIT, WHITE1BIT)) + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite) + + +#define luaC_checkGC(L) { if (G(L)->nblocks >= G(L)->GCthreshold) \ + luaC_step(L); } + + +#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } +#define luaC_objbarrier(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),obj2gco(o)); } -size_t luaC_separateudata (lua_State *L); +size_t luaC_separateudata (lua_State *L, int all); void luaC_callGCTM (lua_State *L); -void luaC_sweep (lua_State *L, int all); -void luaC_collectgarbage (lua_State *L); +void luaC_sweepall (lua_State *L); +void luaC_step (lua_State *L); +void luaC_fullgc (lua_State *L); void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +void luaC_linkupval (lua_State *L, UpVal *uv); +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); #endif diff --git a/src/lib/RCS b/src/lib/RCS new file mode 120000 index 00000000..1ae38936 --- /dev/null +++ b/src/lib/RCS @@ -0,0 +1 @@ +../RCS
\ No newline at end of file diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c index ee2d1339..96131019 100644 --- a/src/lib/lauxlib.c +++ b/src/lib/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.100 2003/04/07 14:35:00 roberto Exp $ +** $Id: lauxlib.c,v 1.110 2004/03/23 16:38:43 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -9,6 +9,7 @@ #include <errno.h> #include <stdarg.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> @@ -74,7 +75,7 @@ static void tag_error (lua_State *L, int narg, int tag) { LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ - lua_getinfo(L, "Snl", &ar); /* get info about it */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; @@ -107,15 +108,13 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ - lua_pushstring(L, tname); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ lua_pushvalue(L, -1); lua_pushstring(L, tname); lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ @@ -124,8 +123,7 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); + lua_getfield(L, LUA_REGISTRYINDEX, tname); } @@ -196,11 +194,25 @@ LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { } +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { + lua_Integer d = lua_tointeger(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, + lua_Integer def) { + if (lua_isnoneornil(L, narg)) return def; + else return luaL_checkinteger(L, narg); +} + + LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); + lua_getfield(L, -1, event); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; @@ -225,24 +237,23 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_reg *l, int nup) { if (libname) { - lua_pushstring(L, libname); - lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */ + /* check whether lib already exists */ + lua_getglobal(L, libname); if (lua_isnil(L, -1)) { /* no? */ lua_pop(L, 1); lua_newtable(L); /* create it */ - lua_pushstring(L, libname); - lua_pushvalue(L, -2); - lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */ + lua_pushvalue(L, -1); + /* register it with given name */ + lua_setglobal(L, libname); } lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { int i; - lua_pushstring(L, l->name); for (i=0; i<nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup+1)); + lua_pushvalue(L, -nup); lua_pushcclosure(L, l->func, nup); - lua_settable(L, -(nup+3)); + lua_setfield(L, -(nup+2), l->name); } lua_pop(L, nup); /* remove upvalues */ } @@ -256,8 +267,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, */ static int checkint (lua_State *L, int topop) { - int n = (int)lua_tonumber(L, -1); - if (n == 0 && !lua_isnumber(L, -1)) n = -1; + int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; lua_pop(L, topop); return n; } @@ -270,9 +280,8 @@ static void getsizes (lua_State *L) { lua_newtable(L); /* create it */ lua_pushvalue(L, -1); /* `size' will be its own metatable */ lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(N).__mode = "k" */ + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ lua_pushvalue(L, -1); lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ } @@ -281,33 +290,23 @@ static void getsizes (lua_State *L) { void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); - lua_pushliteral(L, "n"); - lua_rawget(L, t); - if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ - lua_pushliteral(L, "n"); /* use it */ - lua_pushnumber(L, (lua_Number)n); - lua_rawset(L, t); - } - else { /* use `sizes' */ - getsizes(L); - lua_pushvalue(L, t); - lua_pushnumber(L, (lua_Number)n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ - } + getsizes(L); + lua_pushvalue(L, t); + lua_pushinteger(L, n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ } int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); - lua_pushliteral(L, "n"); /* try t.n */ - lua_rawget(L, t); - if ((n = checkint(L, 1)) >= 0) return n; - getsizes(L); /* else try sizes[t] */ + getsizes(L); /* try sizes[t] */ lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; + lua_getfield(L, t, "n"); /* else try t.n */ + if ((n = checkint(L, 1)) >= 0) return n; for (n = 1; ; n++) { /* else must count elements */ lua_rawgeti(L, t, n); if (lua_isnil(L, -1)) break; @@ -424,7 +423,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { return LUA_REFNIL; /* `nil' has a unique fixed reference */ } lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ - ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */ + 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 */ @@ -447,7 +446,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { t = abs_index(L, t); lua_rawgeti(L, t, FREELIST_REF); lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ - lua_pushnumber(L, (lua_Number)ref); + lua_pushinteger(L, ref); lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ } } @@ -461,6 +460,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { + int extraline; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; @@ -469,6 +469,11 @@ 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; + *size = 1; + return "\n"; + } if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); return (*size > 0) ? lf->buff : NULL; @@ -488,6 +493,7 @@ 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; @@ -495,14 +501,23 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ } - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ - c = ungetc(getc(lf.f), lf.f); - if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ + 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] && lf.f != stdin) { /* binary file? */ fclose(lf.f); lf.f = fopen(filename, "rb"); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ + /* skip eventual `#!...' */ + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + lf.extraline = 0; } + ungetc(c, lf.f); status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ @@ -542,6 +557,22 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, /* }====================================================== */ +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +LUALIB_API lua_State *luaL_newstate (void) { + return lua_newstate(l_alloc, NULL); +} + + /* ** {====================================================== ** compatibility code diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index b6a4baed..42b0355a 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ +** $Id: lbaselib.c,v 1.140 2004/03/09 17:34:35 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -78,10 +78,8 @@ static int luaB_tonumber (lua_State *L) { static int luaB_error (lua_State *L) { int level = luaL_optint(L, 2, 1); - luaL_checkany(L, 1); - if (!lua_isstring(L, 1) || level == 0) - lua_pushvalue(L, 1); /* propagate error message without changes */ - else { /* add extra information */ + lua_settop(L, 1); + if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); @@ -187,15 +185,32 @@ static int luaB_rawset (lua_State *L) { static int luaB_gcinfo (lua_State *L) { - lua_pushnumber(L, (lua_Number)lua_getgccount(L)); - lua_pushnumber(L, (lua_Number)lua_getgcthreshold(L)); - return 2; + lua_pushinteger(L, lua_getgccount(L)); + return 1; } static int luaB_collectgarbage (lua_State *L) { - lua_setgcthreshold(L, luaL_optint(L, 1, 0)); - return 0; + static const char *const opts[] = {"stop", "restart", "collect", "count", + NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, + LUA_GCCOLLECT, LUA_GCCOUNT}; + int o; + int ex; +#if 1 + if (lua_isnumber(L, 1)) { + int v = lua_tointeger(L, 1); + lua_settop(L, 0); + if (v == 0) lua_pushstring(L, "collect"); + else if (v >= 10000) lua_pushstring(L, "stop"); + else lua_pushstring(L, "restart"); + } +#endif + o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); + ex = luaL_optint(L, 2, 0); + luaL_argcheck(L, o >= 0, 1, "invalid option"); + lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); + return 1; } @@ -220,8 +235,7 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - lua_pushliteral(L, "next"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_getglobal(L, "next"); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; @@ -229,19 +243,18 @@ static int luaB_pairs (lua_State *L) { static int luaB_ipairs (lua_State *L) { - lua_Number i = lua_tonumber(L, 2); + int i = (int)lua_tointeger(L, 2); luaL_checktype(L, 1, LUA_TTABLE); if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ - lua_pushliteral(L, "ipairs"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_getglobal(L, "ipairs"); /* return generator, */ lua_pushvalue(L, 1); /* state, */ - lua_pushnumber(L, 0); /* and initial value */ + lua_pushinteger(L, 0); /* and initial value */ return 3; } else { /* `for' step */ i++; /* next value */ - lua_pushnumber(L, i); - lua_rawgeti(L, 1, (int)i); + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); return (lua_isnil(L, -1)) ? 0 : 2; } } @@ -272,11 +285,51 @@ static int luaB_loadfile (lua_State *L) { } +struct Aux_load { + int func; + int res; +}; + + +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + struct Aux_load *al = (struct Aux_load *)ud; + luaL_unref(L, al->res, LUA_REGISTRYINDEX); + lua_getref(L, al->func); + lua_call(L, 0, 1); + if (lua_isnil(L, -1)) { + *size = 0; + return NULL; + } + else if (lua_isstring(L, -1)) { + const char *res = lua_tostring(L, -1); + *size = lua_strlen(L, -1); + al->res = luaL_ref(L, LUA_REGISTRYINDEX); + return res; + } + else luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ +} + + +static int luaB_load (lua_State *L) { + struct Aux_load al; + int status; + const char *cname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + al.func = luaL_ref(L, LUA_REGISTRYINDEX); + al.res = LUA_REFNIL; + status = lua_load(L, generic_reader, &al, cname); + luaL_unref(L, al.func, LUA_REGISTRYINDEX); + luaL_unref(L, al.res, LUA_REGISTRYINDEX); + return load_aux(L, status); +} + + static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); int n = lua_gettop(L); - int status = luaL_loadfile(L, fname); - if (status != 0) lua_error(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); lua_call(L, 0, LUA_MULTRET); return lua_gettop(L) - n; } @@ -325,7 +378,9 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[128]; + char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ + const char *tn = ""; + const void *p = NULL; luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ @@ -339,24 +394,29 @@ static int luaB_tostring (lua_State *L) { case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); return 1; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + return 1; case LUA_TTABLE: - sprintf(buff, "table: %p", lua_topointer(L, 1)); + p = lua_topointer(L, 1); + tn = "table"; break; case LUA_TFUNCTION: - sprintf(buff, "function: %p", lua_topointer(L, 1)); + p = lua_topointer(L, 1); + tn = "function"; break; case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: - sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); + p = lua_touserdata(L, 1); + tn = "userdata"; break; case LUA_TTHREAD: - sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1)); + p = lua_tothread(L, 1); + tn = "thread"; break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - return 1; } - lua_pushstring(L, buff); + sprintf(buff, "%p", p); + lua_pushfstring(L, "%s: %s", tn, buff); return 1; } @@ -441,14 +501,14 @@ static void pushcomposename (lua_State *L) { const char *wild; int n = 1; while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) { - /* is there stack space for prefix, name, and eventual last sufix? */ + /* is there stack space for prefix, name, and eventual last suffix? */ luaL_checkstack(L, 3, "too many marks in a path component"); lua_pushlstring(L, path, wild - path); /* push prefix */ lua_pushvalue(L, 1); /* push package name (in place of MARK) */ path = wild + 1; /* continue after MARK */ n += 2; } - lua_pushstring(L, path); /* push last sufix (`n' already includes this) */ + lua_pushstring(L, path); /* push last suffix (`n' already includes this) */ lua_concat(L, n); } @@ -530,6 +590,7 @@ static const luaL_reg base_funcs[] = { {"loadfile", luaB_loadfile}, {"dofile", luaB_dofile}, {"loadstring", luaB_loadstring}, + {"load", luaB_load}, {"require", luaB_require}, {NULL, NULL} }; @@ -645,23 +706,19 @@ static const luaL_reg co_funcs[] = { static void base_open (lua_State *L) { - lua_pushliteral(L, "_G"); lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ - lua_pushliteral(L, "_VERSION"); lua_pushliteral(L, LUA_VERSION); - lua_rawset(L, -3); /* set global _VERSION */ + lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ /* `newproxy' needs a weaktable as upvalue */ - lua_pushliteral(L, "newproxy"); lua_newtable(L); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(w).__mode = "k" */ + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_rawset(L, -3); /* set global `newproxy' */ - lua_rawset(L, -1); /* set global _G */ + lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ + lua_setfield(L, -1, "_G"); /* set global _G */ } @@ -670,6 +727,6 @@ LUALIB_API int luaopen_base (lua_State *L) { luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); lua_newtable(L); lua_setglobal(L, REQTAB); - return 0; + return 2; } diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c index 6dc9b64c..dd4e0363 100644 --- a/src/lib/ldblib.c +++ b/src/lib/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.80 2003/04/03 13:35:34 roberto Exp $ +** $Id: ldblib.c,v 1.84 2003/11/05 11:59:14 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -19,37 +19,50 @@ static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, i); lua_pushstring(L, v); - lua_rawset(L, -3); + lua_setfield(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { - lua_pushstring(L, i); - lua_pushnumber(L, (lua_Number)v); - lua_rawset(L, -3); + lua_pushinteger(L, v); + lua_setfield(L, -2, i); +} + + +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; + } } static int getinfo (lua_State *L) { lua_Debug ar; - const char *options = luaL_optstring(L, 2, "flnSu"); - if (lua_isnumber(L, 1)) { - if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSu"); + if (lua_isnumber(L, arg+1)) { + if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } - else if (lua_isfunction(L, 1)) { + else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); - lua_pushvalue(L, 1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); } else - return luaL_argerror(L, 1, "function or level expected"); - if (!lua_getinfo(L, options, &ar)) - return luaL_argerror(L, 2, "invalid option"); + return luaL_argerror(L, arg+1, "function or level expected"); + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); lua_newtable(L); for (; *options; options++) { switch (*options) { @@ -70,9 +83,11 @@ static int getinfo (lua_State *L) { settabss(L, "namewhat", ar.namewhat); break; case 'f': - lua_pushliteral(L, "func"); - lua_pushvalue(L, -3); - lua_rawset(L, -3); + if (L == L1) + lua_pushvalue(L, -2); + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, "func"); break; } } @@ -81,12 +96,15 @@ static int getinfo (lua_State *L) { static int getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); if (name) { + lua_xmove(L1, L, 1); lua_pushstring(L, name); lua_pushvalue(L, -2); return 2; @@ -99,11 +117,15 @@ static int getlocal (lua_State *L) { static int setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - luaL_checkany(L, 3); - lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + lua_xmove(L, L1, 1); + lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); return 1; } @@ -141,16 +163,16 @@ static void hookf (lua_State *L, lua_Debug *ar) { {"call", "return", "line", "count", "tail return"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, L); + lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) - lua_pushnumber(L, (lua_Number)ar->currentline); + lua_pushinteger(L, ar->currentline); else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); } - else - lua_pop(L, 1); /* pop result from gettable */ } @@ -174,36 +196,59 @@ static char *unmakemask (int mask, char *smask) { } +static void gethooktable (lua_State *L) { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_newtable(L); + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } +} + + static int sethook (lua_State *L) { - if (lua_isnoneornil(L, 1)) { - lua_settop(L, 1); - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + int arg; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + lua_sethook(L1, NULL, 0, 0); /* turn off hooks */ } else { - const char *smask = luaL_checkstring(L, 2); - int count = luaL_optint(L, 3, 0); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_sethook(L, hookf, makemask(smask, count), count); + const char *smask = luaL_checkstring(L, arg+2); + int count = luaL_optint(L, arg+3, 0); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + lua_sethook(L1, hookf, makemask(smask, count), count); } - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_pushvalue(L, 1); - lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ + gethooktable(L1); + lua_pushlightuserdata(L1, L1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + lua_rawset(L1, -3); /* set new hook */ + lua_pop(L1, 1); /* remove hook table */ return 0; } static int gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); char buff[5]; - int mask = lua_gethookmask(L); - lua_Hook hook = lua_gethook(L); + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ + gethooktable(L1); + lua_pushlightuserdata(L1, L1); + lua_rawget(L1, -2); /* get hook */ + lua_remove(L1, -2); /* remove hook table */ + lua_xmove(L1, L, 1); } lua_pushstring(L, unmakemask(mask, buff)); - lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); + lua_pushinteger(L, lua_gethookcount(L1)); return 3; } @@ -227,27 +272,29 @@ static int debug (lua_State *L) { static int errorfb (lua_State *L) { int level = 1; /* skip level 0 (it's this function) */ int firstpart = 1; /* still before eventual `...' */ + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (lua_gettop(L) == 0) + if (lua_gettop(L) == arg) lua_pushliteral(L, ""); - else if (!lua_isstring(L, 1)) return 1; /* no string message */ + else if (!lua_isstring(L, arg+1)) return 1; /* no string message */ else lua_pushliteral(L, "\n"); lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L, level++, &ar)) { + while (lua_getstack(L1, level++, &ar)) { if (level > LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L, level+LEVELS2, &ar)) + if (!lua_getstack(L1, level+LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } lua_pushliteral(L, "\n\t"); - lua_getinfo(L, "Snl", &ar); + lua_getinfo(L1, "Snl", &ar); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); @@ -268,9 +315,9 @@ static int errorfb (lua_State *L) { ar.short_src, ar.linedefined); } } - lua_concat(L, lua_gettop(L)); + lua_concat(L, lua_gettop(L) - arg); } - lua_concat(L, lua_gettop(L)); + lua_concat(L, lua_gettop(L) - arg); return 1; } @@ -291,9 +338,8 @@ static const luaL_reg dblib[] = { LUALIB_API int luaopen_debug (lua_State *L) { luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); - lua_pushliteral(L, "_TRACEBACK"); lua_pushcfunction(L, errorfb); - lua_settable(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "_TRACEBACK"); return 1; } diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 96b38831..1815c96b 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ +** $Id: liolib.c,v 2.49 2003/10/10 13:29:28 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -37,16 +37,12 @@ ** by default, posix systems get `popen' */ #ifndef USE_POPEN -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 2 +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 2 #define USE_POPEN 1 -#endif -#endif -#endif - -#ifndef USE_POPEN +#else #define USE_POPEN 0 #endif +#endif @@ -65,8 +61,8 @@ #define FILEHANDLE "FILE*" -#define IO_INPUT "_input" -#define IO_OUTPUT "_output" +#define IO_INPUT 1 +#define IO_OUTPUT 2 static int pushresult (lua_State *L, int i, const char *filename) { @@ -80,7 +76,7 @@ static int pushresult (lua_State *L, int i, const char *filename) { lua_pushfstring(L, "%s: %s", filename, strerror(errno)); else lua_pushfstring(L, "%s", strerror(errno)); - lua_pushnumber(L, errno); + lua_pushinteger(L, errno); return 3; } } @@ -127,23 +123,6 @@ static FILE **newfile (lua_State *L) { } -/* -** assumes that top of the stack is the `io' library, and next is -** the `io' metatable -*/ -static void registerfile (lua_State *L, FILE *f, const char *name, - const char *impname) { - lua_pushstring(L, name); - *newfile(L) = f; - if (impname) { - lua_pushstring(L, impname); - lua_pushvalue(L, -2); - lua_settable(L, -6); /* metatable[impname] = file */ - } - lua_settable(L, -3); /* io[name] = file */ -} - - static int aux_close (lua_State *L) { FILE *f = tofile(L, 1); if (f == stdin || f == stdout || f == stderr) @@ -158,10 +137,8 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { - if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { - lua_pushstring(L, IO_OUTPUT); - lua_rawget(L, lua_upvalueindex(1)); - } + if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) + lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); return pushresult(L, aux_close(L), NULL); } @@ -175,7 +152,7 @@ static int io_gc (lua_State *L) { static int io_tostring (lua_State *L) { - char buff[128]; + char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ FILE **f = topfile(L, 1); if (*f == NULL) strcpy(buff, "closed"); @@ -216,17 +193,15 @@ static int io_tmpfile (lua_State *L) { } -static FILE *getiofile (lua_State *L, const char *name) { - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); +static FILE *getiofile (lua_State *L, int f) { + lua_rawgeti(L, lua_upvalueindex(1), f); return tofile(L, -1); } -static int g_iofile (lua_State *L, const char *name, const char *mode) { +static int g_iofile (lua_State *L, int f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); - lua_pushstring(L, name); if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); @@ -239,11 +214,10 @@ static int g_iofile (lua_State *L, const char *name, const char *mode) { tofile(L, 1); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_rawset(L, lua_upvalueindex(1)); + lua_rawseti(L, lua_upvalueindex(1), f); } /* return current value */ - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); + lua_rawgeti(L, lua_upvalueindex(1), f); return 1; } @@ -262,8 +236,7 @@ static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int close) { - lua_pushliteral(L, FILEHANDLE); - lua_rawget(L, LUA_REGISTRYINDEX); + lua_getfield(L, LUA_REGISTRYINDEX, FILEHANDLE); lua_pushvalue(L, idx); lua_pushboolean(L, close); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 3); @@ -279,8 +252,8 @@ static int f_lines (lua_State *L) { static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ - lua_pushstring(L, IO_INPUT); - lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */ + /* will iterate over default input */ + lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); return f_lines(L); } else { @@ -372,7 +345,7 @@ static int g_read (lua_State *L, FILE *f, int first) { success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tonumber(L, n); + size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { @@ -467,18 +440,29 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L, 1); int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); - long offset = luaL_optlong(L, 3, 0); + lua_Integer offset = luaL_optinteger(L, 3, 0); luaL_argcheck(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ else { - lua_pushnumber(L, ftell(f)); + lua_pushinteger(L, ftell(f)); return 1; } } +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L, 1); + int op = luaL_findstring(luaL_checkstring(L, 2), modenames); + luaL_argcheck(L, op != -1, 2, "invalid mode"); + return pushresult(L, setvbuf(f, NULL, mode[op], 0) == 0, NULL); +} + + + static int io_flush (lua_State *L) { return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } @@ -510,6 +494,7 @@ static const luaL_reg flib[] = { {"read", f_read}, {"lines", f_lines}, {"seek", f_seek}, + {"setvbuf", f_setvbuf}, {"write", f_write}, {"close", io_close}, {"__gc", io_gc}, @@ -520,10 +505,14 @@ static const luaL_reg flib[] = { static void createmeta (lua_State *L) { luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ + /* create (and set) default files */ + *newfile(L) = stdin; + lua_rawseti(L, -2, IO_INPUT); + *newfile(L) = stdout; + lua_rawseti(L, -2, IO_OUTPUT); /* file methods */ - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); /* push metatable */ - lua_rawset(L, -3); /* metatable.__index = metatable */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_openlib(L, NULL, flib, 0); } @@ -537,7 +526,7 @@ static void createmeta (lua_State *L) { */ static int io_execute (lua_State *L) { - lua_pushnumber(L, system(luaL_checkstring(L, 1))); + lua_pushinteger(L, system(luaL_checkstring(L, 1))); return 1; } @@ -591,7 +580,7 @@ static int io_clock (lua_State *L) { static void setfield (lua_State *L, const char *key, int value) { lua_pushstring(L, key); - lua_pushnumber(L, value); + lua_pushinteger(L, value); lua_rawset(L, -3); } @@ -603,8 +592,7 @@ static void setboolfield (lua_State *L, const char *key, int value) { static int getboolfield (lua_State *L, const char *key) { int res; - lua_pushstring(L, key); - lua_gettable(L, -2); + lua_getfield(L, -1, key); res = lua_toboolean(L, -1); lua_pop(L, 1); return res; @@ -613,12 +601,11 @@ static int getboolfield (lua_State *L, const char *key) { static int getfield (lua_State *L, const char *key, int d) { int res; - lua_pushstring(L, key); - lua_gettable(L, -2); + lua_getfield(L, -1, key); if (lua_isnumber(L, -1)) - res = (int)(lua_tonumber(L, -1)); + res = (int)lua_tointeger(L, -1); else { - if (d == -2) + if (d < 0) return luaL_error(L, "field `%s' missing in date table", key); res = d; } @@ -629,10 +616,9 @@ static int getfield (lua_State *L, const char *key, int d) { static int io_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = (time_t)(luaL_optnumber(L, 2, -1)); + lua_Number n = luaL_optnumber(L, 2, -1); + time_t t = (n == -1) ? time(NULL) : (time_t)n; struct tm *stm; - if (t == (time_t)(-1)) /* no time given? */ - t = time(NULL); /* use current time */ if (*s == '!') { /* UTC? */ stm = gmtime(&t); s++; /* skip `!' */ @@ -642,7 +628,7 @@ static int io_date (lua_State *L) { if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { - lua_newtable(L); + lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); @@ -675,9 +661,9 @@ static int io_time (lua_State *L) { ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -2); - ts.tm_mon = getfield(L, "month", -2) - 1; - ts.tm_year = getfield(L, "year", -2) - 1900; + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); if (t == (time_t)(-1)) @@ -742,9 +728,15 @@ LUALIB_API int luaopen_io (lua_State *L) { lua_pushvalue(L, -1); luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* put predefined file handles into `io' table */ - registerfile(L, stdin, "stdin", IO_INPUT); - registerfile(L, stdout, "stdout", IO_OUTPUT); - registerfile(L, stderr, "stderr", NULL); + lua_pushliteral(L, "stdin"); + lua_rawgeti(L, 2, IO_INPUT); + lua_rawset(L, 3); + lua_pushliteral(L, "stdout"); + lua_rawgeti(L, 2, IO_OUTPUT); + lua_rawset(L, 3); + lua_pushliteral(L, "stderr"); + *newfile(L) = stderr; + lua_rawset(L, 3); return 1; } diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index f074a56e..6041b2e3 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.56 2003/03/11 12:30:37 roberto Exp $ +** $Id: lmathlib.c,v 1.59 2003/11/05 11:59:14 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -128,7 +128,7 @@ static int math_rad (lua_State *L) { static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); - lua_pushnumber(L, e); + lua_pushinteger(L, e); return 2; } @@ -179,14 +179,14 @@ static int math_random (lua_State *L) { case 1: { /* only upper limit */ int u = luaL_checkint(L, 1); luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */ + lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ int l = luaL_checkint(L, 1); int u = luaL_checkint(L, 2); luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */ + lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); @@ -235,12 +235,10 @@ static const luaL_reg mathlib[] = { */ LUALIB_API int luaopen_math (lua_State *L) { luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); - lua_pushliteral(L, "pi"); lua_pushnumber(L, PI); - lua_settable(L, -3); - lua_pushliteral(L, "__pow"); + lua_setfield(L, -2, "pi"); lua_pushcfunction(L, math_pow); - lua_settable(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "__pow"); return 1; } diff --git a/src/lib/loadlib.c b/src/lib/loadlib.c index ac4d697a..2a6b39e1 100644 --- a/src/lib/loadlib.c +++ b/src/lib/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.4 2003/04/07 20:11:53 roberto Exp $ +** $Id: loadlib.c,v 1.5 2003/05/14 21:01:53 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h * @@ -136,33 +136,13 @@ static int loadlib(lua_State *L) ** Those systems support dlopen, so they should have defined USE_DLOPEN. ** The default (no)implementation gives them a special error message. */ -#ifdef linux -#define LOADLIB -#endif - -#ifdef sun -#define LOADLIB -#endif - -#ifdef sgi -#define LOADLIB -#endif - -#ifdef BSD -#define LOADLIB -#endif - -#ifdef _WIN32 -#define LOADLIB -#endif - -#ifdef LOADLIB -#undef LOADLIB +#if defined(linux) || defined(sun) || defined(sgi) || defined(BSD) || defined(_WIN32) #define LOADLIB "`loadlib' not installed (check your Lua configuration)" #else #define LOADLIB "`loadlib' not supported" #endif + static int loadlib(lua_State *L) { lua_pushnil(L); diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index 8752e3ab..36b226d2 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.98 2003/04/03 13:35:34 roberto Exp $ +** $Id: lstrlib.c,v 1.101 2004/01/02 11:54:14 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -25,13 +25,13 @@ #endif -typedef long sint32; /* a signed version for size_t */ +typedef lua_Integer sint32; /* a signed version for size_t */ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); - lua_pushnumber(L, (lua_Number)l); + lua_pushinteger(L, l); return 1; } @@ -45,8 +45,8 @@ static sint32 posrelat (sint32 pos, size_t len) { static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 start = posrelat(luaL_checklong(L, 2), l); - sint32 end = posrelat(luaL_optlong(L, 3, -1), l); + sint32 start = posrelat(luaL_checkinteger(L, 2), l); + sint32 end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > (sint32)l) end = (sint32)l; if (start <= end) @@ -56,6 +56,17 @@ static int str_sub (lua_State *L) { } +static int str_reverse (lua_State *L) { + size_t l; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + while (l--) luaL_putchar(&b, s[l]); + luaL_pushresult(&b); + return 1; +} + + static int str_lower (lua_State *L) { size_t l; size_t i; @@ -97,10 +108,10 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 pos = posrelat(luaL_optlong(L, 2, 1), l); + sint32 pos = posrelat(luaL_optinteger(L, 2, 1), l); if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */ return 0; /* no answer */ - lua_pushnumber(L, uchar(s[pos-1])); + lua_pushinteger(L, uchar(s[pos-1])); return 1; } @@ -189,7 +200,7 @@ static const char *luaI_classend (MatchState *ms, const char *p) { switch (*p++) { case ESC: { if (*p == '\0') - luaL_error(ms->L, "malformed pattern (ends with `%')"); + luaL_error(ms->L, "malformed pattern (ends with `%%')"); return p+1; } case '[': { @@ -452,7 +463,7 @@ static void push_onecapture (MatchState *ms, int i) { int l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) - lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1)); + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } @@ -477,7 +488,7 @@ static int str_find (lua_State *L) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); - sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1; + sint32 init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; else if ((size_t)(init) > l1) init = (sint32)l1; if (lua_toboolean(L, 4) || /* explicit request? */ @@ -485,8 +496,8 @@ static int str_find (lua_State *L) { /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { - lua_pushnumber(L, (lua_Number)(s2-s+1)); - lua_pushnumber(L, (lua_Number)(s2-s+l2)); + lua_pushinteger(L, s2-s+1); + lua_pushinteger(L, s2-s+l2); return 2; } } @@ -501,8 +512,8 @@ static int str_find (lua_State *L) { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { - lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */ - lua_pushnumber(L, (lua_Number)(res-s)); /* end */ + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ return push_captures(&ms, NULL, 0) + 2; } } while (s1++<ms.src_end && !anchor); @@ -521,7 +532,7 @@ static int gfind_aux (lua_State *L) { ms.L = L; ms.src_init = s; ms.src_end = s+ls; - for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3)); + for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { const char *e; @@ -529,7 +540,7 @@ static int gfind_aux (lua_State *L) { if ((e = match(&ms, src, p)) != NULL) { int newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushnumber(L, (lua_Number)newstart); + lua_pushinteger(L, newstart); lua_replace(L, lua_upvalueindex(3)); return push_captures(&ms, src, e); } @@ -542,7 +553,7 @@ static int gfind (lua_State *L) { luaL_checkstring(L, 1); luaL_checkstring(L, 2); lua_settop(L, 2); - lua_pushnumber(L, 0); + lua_pushinteger(L, 0); lua_pushcclosure(L, gfind_aux, 3); return 1; } @@ -616,7 +627,7 @@ static int str_gsub (lua_State *L) { } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); - lua_pushnumber(L, (lua_Number)n); /* number of substitutions */ + lua_pushinteger(L, n); /* number of substitutions */ return 2; } @@ -671,7 +682,7 @@ static const char *scanformat (lua_State *L, const char *strfrmt, luaL_error(L, "invalid format (width or precision too long)"); if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ luaL_error(L, "invalid format (too long)"); - form[0] = '%'; + form[0] = ESC; strncpy(form+1, strfrmt, p-strfrmt+1); form[p-strfrmt+2] = 0; return p; @@ -686,9 +697,9 @@ static int str_format (lua_State *L) { luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { - if (*strfrmt != '%') + if (*strfrmt != ESC) luaL_putchar(&b, *strfrmt++); - else if (*++strfrmt == '%') + else if (*++strfrmt == ESC) luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ @@ -746,6 +757,7 @@ static int str_format (lua_State *L) { static const luaL_reg strlib[] = { {"len", str_len}, {"sub", str_sub}, + {"reverse", str_reverse}, {"lower", str_lower}, {"upper", str_upper}, {"char", str_char}, diff --git a/src/lib/ltablib.c b/src/lib/ltablib.c index c9bb2d1b..c38da36f 100644 --- a/src/lib/ltablib.c +++ b/src/lib/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.21 2003/04/03 13:35:34 roberto Exp $ +** $Id: ltablib.c,v 1.22 2003/10/07 20:13:41 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ static int luaB_foreachi (lua_State *L) { luaL_checktype(L, 2, LUA_TFUNCTION); for (i=1; i<=n; i++) { lua_pushvalue(L, 2); /* function */ - lua_pushnumber(L, (lua_Number)i); /* 1st argument */ + lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ lua_call(L, 2, 1); if (!lua_isnil(L, -1)) @@ -54,7 +54,7 @@ static int luaB_foreach (lua_State *L) { static int luaB_getn (lua_State *L) { - lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); + lua_pushinteger(L, aux_getn(L, 1)); return 1; } @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.119 2003/03/24 12:39:34 roberto Exp $ +** $Id: llex.c,v 2.2 2004/03/12 19:53:56 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -22,9 +22,19 @@ -#define next(LS) (LS->current = zgetc(LS->z)) +#define next(ls) (ls->current = zgetc(ls->z)) +#define save(ls,c) { \ + Mbuffer *b = ls->buff; \ + if (b->n + 1 > b->buffsize) \ + luaZ_resizebuffer(ls->L, b, ((b->buffsize*2) + LUA_MINBUFFER)); \ + b->buffer[b->n++] = cast(char, c); } + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + /* ORDER RESERVED */ static const char *const token2string [] = { @@ -51,85 +61,75 @@ void luaX_init (lua_State *L) { #define MAXSRC 80 -void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) { - if (val > limit) { - msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit); - luaX_syntaxerror(ls, msg); +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + lua_assert(token == (unsigned char)token); + return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : + luaO_pushfstring(ls->L, "%c", token); } + else + return token2string[token-FIRST_RESERVED]; } -void luaX_errorline (LexState *ls, const char *s, const char *token, int line) { - lua_State *L = ls->L; - char buff[MAXSRC]; - luaO_chunkid(buff, getstr(ls->source), MAXSRC); - luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token); - luaD_throw(L, LUA_ERRSYNTAX); -} - - -static void luaX_error (LexState *ls, const char *s, const char *token) { - luaX_errorline(ls, s, token, ls->linenumber); -} - - -void luaX_syntaxerror (LexState *ls, const char *msg) { - const char *lasttoken; - switch (ls->t.token) { +static const char *txtToken (LexState *ls, int token) { + switch (token) { case TK_NAME: - lasttoken = getstr(ls->t.seminfo.ts); - break; case TK_STRING: case TK_NUMBER: - lasttoken = luaZ_buffer(ls->buff); - break; + save(ls, '\0'); + return luaZ_buffer(ls->buff); default: - lasttoken = luaX_token2str(ls, ls->t.token); - break; + return luaX_token2str(ls, token); } - luaX_error(ls, msg, lasttoken); } -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { - lua_assert(token == (unsigned char)token); - return luaO_pushfstring(ls->L, "%c", token); - } - else - return token2string[token-FIRST_RESERVED]; +void luaX_lexerror (LexState *ls, const char *msg, int token) { + char buff[MAXSRC]; + luaO_chunkid(buff, getstr(ls->source), MAXSRC); + msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + if (token) + luaO_pushfstring(ls->L, "%s near `%s'", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); } -static void luaX_lexerror (LexState *ls, const char *s, int token) { - if (token == TK_EOS) - luaX_error(ls, s, luaX_token2str(ls, token)); - else - luaX_error(ls, s, luaZ_buffer(ls->buff)); +void luaX_syntaxerror (LexState *ls, const char *msg) { + luaX_lexerror(ls, msg, ls->t.token); } -static void inclinenumber (LexState *LS) { - next(LS); /* skip `\n' */ - ++LS->linenumber; - luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk"); +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); + TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ + if (ttisnil(o)) + setbvalue(o, 1); /* make sure `str' will not be collected */ + return ts; } -void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { - LS->L = L; - LS->lookahead.token = TK_EOS; /* no look-ahead token */ - LS->z = z; - LS->fs = NULL; - LS->linenumber = 1; - LS->lastline = 1; - LS->source = source; - next(LS); /* read first char */ - if (LS->current == '#') { - do { /* skip first line */ - next(LS); - } while (LS->current != '\n' && LS->current != EOZ); - } +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip `\n' or `\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip `\n\r' or `\r\n' */ + if (++ls->linenumber >= MAX_INT) + luaX_syntaxerror(ls, "chunk has too many lines"); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { + ls->L = L; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + next(ls); /* read first char */ } @@ -141,242 +141,229 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { */ -/* use buffer to store names, literal strings and numbers */ -/* extra space to allocate when growing buffer */ -#define EXTRABUFF 32 - -/* maximum number of chars that can be read without checking buffer size */ -#define MAXNOCHECK 5 - -#define checkbuffer(LS, len) \ - if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \ - luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF) - -#define save(LS, c, l) \ - (luaZ_buffer((LS)->buff)[l++] = cast(char, c)) -#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS)) - - -static size_t readname (LexState *LS) { - size_t l = 0; - checkbuffer(LS, l); - do { - checkbuffer(LS, l); - save_and_next(LS, l); - } while (isalnum(LS->current) || LS->current == '_'); - save(LS, '\0', l); - return l-1; +static void save_and_next (LexState *ls) { + save(ls, ls->current); + next(ls); } + /* LUA_NUMBER */ -static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) { - size_t l = 0; - checkbuffer(LS, l); - if (comma) save(LS, '.', l); - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); +static void read_numeral (LexState *ls, SemInfo *seminfo) { + while (isdigit(ls->current)) { + save_and_next(ls); } - if (LS->current == '.') { - save_and_next(LS, l); - if (LS->current == '.') { - save_and_next(LS, l); - save(LS, '\0', l); - luaX_lexerror(LS, + if (ls->current == '.') { + save_and_next(ls); + if (ls->current == '.') { + save_and_next(ls); + luaX_lexerror(ls, "ambiguous syntax (decimal point x string concatenation)", TK_NUMBER); } } - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); + while (isdigit(ls->current)) { + save_and_next(ls); } - if (LS->current == 'e' || LS->current == 'E') { - save_and_next(LS, l); /* read `E' */ - if (LS->current == '+' || LS->current == '-') - save_and_next(LS, l); /* optional exponent sign */ - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); + if (ls->current == 'e' || ls->current == 'E') { + save_and_next(ls); /* read `E' */ + if (ls->current == '+' || ls->current == '-') + save_and_next(ls); /* optional exponent sign */ + while (isdigit(ls->current)) { + save_and_next(ls); } } - save(LS, '\0', l); - if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r)) - luaX_lexerror(LS, "malformed number", TK_NUMBER); + save(ls, '\0'); + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) + luaX_lexerror(ls, "malformed number", TK_NUMBER); } -static void read_long_string (LexState *LS, SemInfo *seminfo) { +static int skip_ast (LexState *ls) { + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '*') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, int ast) { int cont = 0; - size_t l = 0; - checkbuffer(LS, l); - save(LS, '[', l); /* save first `[' */ - save_and_next(LS, l); /* pass the second `[' */ - if (LS->current == '\n') /* string starts with a newline? */ - inclinenumber(LS); /* skip it */ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ for (;;) { - checkbuffer(LS, l); - switch (LS->current) { + switch (ls->current) { case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, (seminfo) ? "unfinished long string" : + luaX_lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ case '[': - save_and_next(LS, l); - if (LS->current == '[') { + if (skip_ast(ls) == ast) { + save_and_next(ls); /* skip 2nd `[' */ cont++; - save_and_next(LS, l); } continue; case ']': - save_and_next(LS, l); - if (LS->current == ']') { - if (cont == 0) goto endloop; - cont--; - save_and_next(LS, l); + if (skip_ast(ls) == ast) { + save_and_next(ls); /* skip 2nd `]' */ + if (cont-- == 0) goto endloop; } continue; case '\n': - save(LS, '\n', l); - inclinenumber(LS); - if (!seminfo) l = 0; /* reset buffer to avoid wasting space */ + case '\r': + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ continue; default: - save_and_next(LS, l); + if (seminfo) save_and_next(ls); + else next(ls); } } endloop: - save_and_next(LS, l); /* skip the second `]' */ - save(LS, '\0', l); if (seminfo) - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5); + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + ast), + luaZ_bufflen(ls->buff) - 2*(2 + ast)); } -static void read_string (LexState *LS, int del, SemInfo *seminfo) { - size_t l = 0; - checkbuffer(LS, l); - save_and_next(LS, l); - while (LS->current != del) { - checkbuffer(LS, l); - switch (LS->current) { +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); + while (ls->current != del) { + switch (ls->current) { case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_EOS); - break; /* to avoid warnings */ + luaX_lexerror(ls, "unfinished string", TK_EOS); + continue; /* to avoid warnings */ case '\n': - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': - next(LS); /* do not save the `\' */ - switch (LS->current) { - case 'a': save(LS, '\a', l); next(LS); break; - case 'b': save(LS, '\b', l); next(LS); break; - case 'f': save(LS, '\f', l); next(LS); break; - case 'n': save(LS, '\n', l); next(LS); break; - case 'r': save(LS, '\r', l); next(LS); break; - case 't': save(LS, '\t', l); next(LS); break; - case 'v': save(LS, '\v', l); next(LS); break; - case '\n': save(LS, '\n', l); inclinenumber(LS); break; - case EOZ: break; /* will raise an error next loop */ + case '\r': + luaX_lexerror(ls, "unfinished string", TK_STRING); + continue; /* to avoid warnings */ + case '\\': { + int c; + next(ls); /* do not save the `\' */ + switch (ls->current) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\n': /* go through */ + case '\r': save(ls, '\n'); inclinenumber(ls); continue; + case EOZ: continue; /* will raise an error next loop */ default: { - if (!isdigit(LS->current)) - save_and_next(LS, l); /* handles \\, \", \', and \? */ + if (!isdigit(ls->current)) + save_and_next(ls); /* handles \\, \", \', and \? */ else { /* \xxx */ - int c = 0; int i = 0; + c = 0; do { - c = 10*c + (LS->current-'0'); - next(LS); - } while (++i<3 && isdigit(LS->current)); - if (c > UCHAR_MAX) { - save(LS, '\0', l); - luaX_lexerror(LS, "escape sequence too large", TK_STRING); - } - save(LS, c, l); + c = 10*c + (ls->current-'0'); + next(ls); + } while (++i<3 && isdigit(ls->current)); + if (c > UCHAR_MAX) + luaX_lexerror(ls, "escape sequence too large", TK_STRING); + save(ls, c); } + continue; } } - break; + save(ls, c); + next(ls); + continue; + } default: - save_and_next(LS, l); + save_and_next(ls); } } - save_and_next(LS, l); /* skip delimiter */ - save(LS, '\0', l); - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3); + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); } -int luaX_lex (LexState *LS, SemInfo *seminfo) { +int luaX_lex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); for (;;) { - switch (LS->current) { - - case '\n': { - inclinenumber(LS); + switch (ls->current) { + case '\n': + case '\r': { + inclinenumber(ls); continue; } case '-': { - next(LS); - if (LS->current != '-') return '-'; + next(ls); + if (ls->current != '-') return '-'; /* else is a comment */ - next(LS); - if (LS->current == '[' && (next(LS), LS->current == '[')) - read_long_string(LS, NULL); /* long comment */ - else /* short comment */ - while (LS->current != '\n' && LS->current != EOZ) - next(LS); + next(ls); + if (ls->current == '[') { + int ast = skip_ast(ls); + luaZ_resetbuffer(ls->buff); /* `skip_ast' may dirty the buffer */ + if (ast >= 0) { + read_long_string(ls, NULL, ast); /* long comment */ + luaZ_resetbuffer(ls->buff); + continue; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); continue; } case '[': { - next(LS); - if (LS->current != '[') return '['; - else { - read_long_string(LS, seminfo); + int ast = skip_ast(ls); + if (ast >= 0) { + read_long_string(ls, seminfo, ast); return TK_STRING; } + else if (ast == -1) return '['; + else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { - next(LS); - if (LS->current != '=') return '='; - else { next(LS); return TK_EQ; } + next(ls); + if (ls->current != '=') return '='; + else { next(ls); return TK_EQ; } } case '<': { - next(LS); - if (LS->current != '=') return '<'; - else { next(LS); return TK_LE; } + next(ls); + if (ls->current != '=') return '<'; + else { next(ls); return TK_LE; } } case '>': { - next(LS); - if (LS->current != '=') return '>'; - else { next(LS); return TK_GE; } + next(ls); + if (ls->current != '=') return '>'; + else { next(ls); return TK_GE; } } case '~': { - next(LS); - if (LS->current != '=') return '~'; - else { next(LS); return TK_NE; } + next(ls); + if (ls->current != '=') return '~'; + else { next(ls); return TK_NE; } } case '"': case '\'': { - read_string(LS, LS->current, seminfo); + read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { - next(LS); - if (LS->current == '.') { - next(LS); - if (LS->current == '.') { - next(LS); + save_and_next(ls); + if (ls->current == '.') { + next(ls); + if (ls->current == '.') { + next(ls); return TK_DOTS; /* ... */ } else return TK_CONCAT; /* .. */ } - else if (!isdigit(LS->current)) return '.'; + else if (!isdigit(ls->current)) return '.'; else { - read_numeral(LS, 1, seminfo); + read_numeral(ls, seminfo); return TK_NUMBER; } } @@ -384,29 +371,33 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) { return TK_EOS; } default: { - if (isspace(LS->current)) { - next(LS); + if (isspace(ls->current)) { + lua_assert(!currIsNewline(ls)); + next(ls); continue; } - else if (isdigit(LS->current)) { - read_numeral(LS, 0, seminfo); + else if (isdigit(ls->current)) { + read_numeral(ls, seminfo); return TK_NUMBER; } - else if (isalpha(LS->current) || LS->current == '_') { + else if (isalpha(ls->current) || ls->current == '_') { /* identifier or reserved word */ - size_t l = readname(LS); - TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l); + TString *ts; + do { + save_and_next(ls); + } while (isalnum(ls->current) || ls->current == '_'); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ return ts->tsv.reserved - 1 + FIRST_RESERVED; - seminfo->ts = ts; - return TK_NAME; + else { + seminfo->ts = ts; + return TK_NAME; + } } else { - int c = LS->current; - if (iscntrl(c)) - luaX_error(LS, "invalid control char", - luaO_pushfstring(LS->L, "char(%d)", c)); - next(LS); + int c = ls->current; + next(ls); return c; /* single-char tokens (+ - / ...) */ } } @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.47 2003/02/28 17:19:47 roberto Exp $ +** $Id: llex.h,v 1.50 2004/03/12 19:53:56 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -65,10 +65,10 @@ typedef struct LexState { void luaX_init (lua_State *L); void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source); +TString *luaX_newstring (LexState *LS, const char *str, size_t l); int luaX_lex (LexState *LS, SemInfo *seminfo); -void luaX_checklimit (LexState *ls, int val, int limit, const char *msg); +void luaX_lexerror (LexState *ls, const char *msg, int token); void luaX_syntaxerror (LexState *ls, const char *s); -void luaX_errorline (LexState *ls, const char *s, const char *token, int line); const char *luaX_token2str (LexState *ls, int token); diff --git a/src/llimits.h b/src/llimits.h index 343c9226..6a2e00bd 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.52 2003/02/20 19:33:23 roberto Exp $ +** $Id: llimits.h,v 1.57 2003/12/01 16:33:30 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -22,15 +22,13 @@ /* avoid overflows in comparison */ #if INT_MAX-20 < 32760 #define BITS_INT 16 -#else -#if INT_MAX > 2147483640L +#elif INT_MAX > 2147483640L /* machine has at least 32 bits */ #define BITS_INT 32 #else #error "you must define BITS_INT with number of bits in an integer" #endif #endif -#endif /* @@ -40,20 +38,43 @@ ** any machine, but may not be optimal. */ -/* an unsigned integer to hold hash values */ -typedef unsigned int lu_hash; -/* its signed equivalent */ -typedef int ls_hash; -/* an unsigned integer big enough to count the total memory used by Lua; */ -/* it should be at least as large as size_t */ -typedef unsigned long lu_mem; +/* +** an unsigned integer with at least 32 bits +*/ +#ifndef LUA_UINT32 +#define LUA_UINT32 unsigned long +#endif + +typedef LUA_UINT32 lu_int32; + + +/* +** a signed integer with at least 32 bits +*/ +#ifndef LUA_INT32 +#define LUA_INT32 long +#define LUA_MAXINT32 LONG_MAX +#endif + +typedef LUA_INT32 l_int32; + -#define MAX_LUMEM ULONG_MAX +/* +** an unsigned integer big enough to count the total memory used by Lua; +** it should be at least as large as `size_t' +*/ +typedef lu_int32 lu_mem; + + +/* +** a signed integer big enough to count the total memory used by Lua; +** it should be at least as large as `size_t' +*/ +typedef l_int32 l_mem; +#define MAXLMEM LUA_MAXINT32 -/* an integer big enough to count the number of strings in use */ -typedef long ls_nstr; /* chars used as small naturals (so that `char' is reserved for characters) */ typedef unsigned char lu_byte; @@ -69,7 +90,7 @@ typedef unsigned char lu_byte; ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ -#define IntPoint(p) ((lu_hash)(p)) +#define IntPoint(p) ((unsigned int)(p)) @@ -114,7 +135,7 @@ typedef LUA_UACNUMBER l_uacNumber; ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ -typedef unsigned long Instruction; +typedef lu_int32 Instruction; /* maximum depth for calls (unsigned short) */ @@ -133,7 +154,7 @@ typedef unsigned long Instruction; #endif -/* maximum size for the C stack */ +/* maximum size for the virtual stack of a C function */ #ifndef LUA_MAXCSTACK #define LUA_MAXCSTACK 2048 #endif @@ -145,19 +166,13 @@ typedef unsigned long Instruction; /* maximum number of variables declared in a function */ #ifndef MAXVARS -#define MAXVARS 200 /* arbitrary limit (<MAXSTACK) */ +#define MAXVARS 200 /* <MAXSTACK */ #endif /* maximum number of upvalues per function */ #ifndef MAXUPVALUES -#define MAXUPVALUES 32 -#endif - - -/* maximum number of parameters in a function */ -#ifndef MAXPARAMS -#define MAXPARAMS 100 /* arbitrary limit (<MAXLOCALS) */ +#define MAXUPVALUES 32 /* <MAXSTACK */ #endif @@ -1,11 +1,11 @@ /* -** $Id: lmem.c,v 1.61 2002/12/04 17:38:31 roberto Exp $ +** $Id: lmem.c,v 1.63 2003/11/27 18:18:37 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stddef.h> #define lmem_c @@ -20,21 +20,23 @@ /* -** definition for realloc function. It must assure that l_realloc(NULL, -** 0, x) allocates a new block (ANSI C assures that). (`os' is the old -** block size; some allocators may use that.) +** About the realloc function: +** void * realloc (void *ud, void *ptr, size_t osize, size_t nsize); +** (`osize' is the old size, `nsize' is the new size) +** +** Lua ensures that (ptr == NULL) iff (osize == 0). +** +** * realloc(ud, NULL, 0, x) creates a new block of size `x' +** +** * realloc(ud, p, x, 0) frees the block `p' +** (in this specific case, realloc must return NULL). +** particularly, realloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ANSI C) +** +** realloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) */ -#ifndef l_realloc -#define l_realloc(b,os,s) realloc(b,s) -#endif -/* -** definition for free function. (`os' is the old block size; some -** allocators may use that.) -*/ -#ifndef l_free -#define l_free(b,os) free(b) -#endif #define MINSIZEARRAY 4 @@ -43,13 +45,16 @@ void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, int limit, const char *errormsg) { void *newblock; - int newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - else if (*size >= limit/2) { /* cannot double it? */ - if (*size < limit - MINSIZEARRAY) /* try something smaller... */ - newsize = limit; /* still have at least MINSIZEARRAY free places */ - else luaG_runerror(L, errormsg); + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit - MINSIZEARRAY) /* try something smaller... */ + luaG_runerror(L, errormsg); + newsize = limit; /* still have at least MINSIZEARRAY free places */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ } newblock = luaM_realloc(L, block, cast(lu_mem, *size)*cast(lu_mem, size_elems), @@ -62,30 +67,17 @@ void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, /* ** generic allocation routine. */ -void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) { - lua_assert((oldsize == 0) == (block == NULL)); - if (size == 0) { - if (block != NULL) { - l_free(block, oldsize); - block = NULL; - } - else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */ - } - else if (size >= MAX_SIZET) +void *luaM_realloc (lua_State *L, void *block, lu_mem osize, lu_mem nsize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + if (nsize >= MAX_SIZET) luaG_runerror(L, "memory allocation error: block too big"); - else { - block = l_realloc(block, oldsize, size); - if (block == NULL) { - if (L) - luaD_throw(L, LUA_ERRMEM); - else return NULL; /* error before creating state! */ - } - } - if (L) { - lua_assert(G(L) != NULL && G(L)->nblocks > 0); - G(L)->nblocks -= oldsize; - G(L)->nblocks += size; - } + block = (*g->realloc)(g->ud, block, osize, nsize); + if (block == NULL && nsize > 0) + luaD_throw(L, LUA_ERRMEM); + lua_assert((nsize == 0) == (block == NULL)); + g->nblocks -= osize; + g->nblocks += nsize; return block; } diff --git a/src/lobject.c b/src/lobject.c index 9522b6e8..f273796b 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 1.97 2003/04/03 13:35:34 roberto Exp $ +** $Id: lobject.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -27,7 +27,7 @@ #endif -const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; +const TValue luaO_nilobject = {LUA_TNIL, {NULL}}; /* @@ -45,33 +45,24 @@ int luaO_int2fb (unsigned int x) { int luaO_log2 (unsigned int x) { - static const lu_byte log_8[255] = { - 0, - 1,1, - 2,2,2,2, - 3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + static const lu_byte log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; - if (x >= 0x00010000) { - if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24; - else return log_8[((x>>16) & 0xff) - 1]+16; - } - else { - if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8; - else if (x) return log_8[(x & 0xff) - 1]; - return -1; /* special `log' for 0 */ - } + int l = -1; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; + } -int luaO_rawequalObj (const TObject *t1, const TObject *t2) { +int luaO_rawequalObj (const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2)) return 0; else switch (ttype(t1)) { case LUA_TNIL: @@ -102,7 +93,7 @@ int luaO_str2d (const char *s, lua_Number *result) { static void pushstr (lua_State *L, const char *str) { - setsvalue2s(L->top, luaS_new(L, str)); + setsvalue2s(L, L->top, luaS_new(L, str)); incr_top(L); } @@ -114,7 +105,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt)); + setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { case 's': @@ -138,7 +129,14 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { case '%': pushstr(L, "%"); break; - default: lua_assert(0); + default: { + char buff[3]; + buff[0] = '%'; + buff[1] = *(e+1); + buff[2] = '\0'; + pushstr(L, buff); + break; + } } n += 2; fmt = e+2; diff --git a/src/lobject.h b/src/lobject.h index 321a7e06..d5176a23 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,13 +1,17 @@ /* -** $Id: lobject.h,v 1.159 2003/03/18 12:50:04 roberto Exp $ +** $Id: lobject.h,v 2.4 2004/03/15 21:04:33 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ + #ifndef lobject_h #define lobject_h +#include <stdarg.h> + + #include "llimits.h" #include "lua.h" @@ -58,12 +62,12 @@ typedef union { /* -** Lua values (or `tagged objects') +** Tagged Values */ -typedef struct lua_TObject { +typedef struct lua_TValue { int tt; Value value; -} TObject; +} TValue; /* Macros to test type */ @@ -82,8 +86,10 @@ typedef struct lua_TObject { #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) -#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) -#define uvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#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 hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) @@ -91,59 +97,69 @@ typedef struct lua_TObject { #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) +/* +** for internal debug only +*/ +#define checkconsistency(obj) \ + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + +#define checkliveness(g,obj) \ + lua_assert(!iscollectable(obj) || \ + ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + + /* Macros to set values */ +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) + #define setnvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TNUMBER; i_o->value.n=(x); } + { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } #define chgnvalue(obj,x) \ check_exp(ttype(obj)==LUA_TNUMBER, (obj)->value.n=(x)) #define setpvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TLIGHTUSERDATA; i_o->value.p=(x); } + { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } #define setbvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TBOOLEAN; i_o->value.b=(x); } + { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } -#define setsvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TSTRING; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TSTRING); } +#define setsvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + checkliveness(G(L),i_o); } -#define setuvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TUSERDATA; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); } +#define setuvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + checkliveness(G(L),i_o); } -#define setthvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TTHREAD; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TTHREAD); } +#define setthvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + checkliveness(G(L),i_o); } -#define setclvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TFUNCTION); } +#define setclvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + checkliveness(G(L),i_o); } -#define sethvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TTABLE; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TTABLE); } - -#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) +#define sethvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + checkliveness(G(L),i_o); } +#define setptvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + checkliveness(G(L),i_o); } -/* -** for internal debug only -*/ -#define checkconsistency(obj) \ - lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) -#define setobj(obj1,obj2) \ - { const TObject *o2=(obj2); TObject *o1=(obj1); \ - checkconsistency(o2); \ - o1->tt=o2->tt; o1->value = o2->value; } +#define setobj(L,obj1,obj2) \ + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->tt=o2->tt; o1->value = o2->value; \ + checkliveness(G(L),o1); } /* @@ -155,6 +171,8 @@ typedef struct lua_TObject { /* to stack (not from same stack) */ #define setobj2s setobj #define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj /* to table */ @@ -170,7 +188,7 @@ typedef struct lua_TObject { -typedef TObject *StkId; /* index to stack elements */ +typedef TValue *StkId; /* index to stack elements */ /* @@ -181,7 +199,7 @@ typedef union TString { struct { CommonHeader; lu_byte reserved; - lu_hash hash; + unsigned int hash; size_t len; } tsv; } TString; @@ -209,7 +227,7 @@ typedef union Udata { */ typedef struct Proto { CommonHeader; - TObject *k; /* constants used by the function */ + TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ @@ -245,8 +263,8 @@ typedef struct LocVar { typedef struct UpVal { CommonHeader; - TObject *v; /* points to stack or to its own value */ - TObject value; /* the value (when closed) */ + TValue *v; /* points to stack or to its own value */ + TValue value; /* the value (when closed) */ } UpVal; @@ -260,14 +278,14 @@ typedef struct UpVal { typedef struct CClosure { ClosureHeader; lua_CFunction f; - TObject upvalue[1]; + TValue upvalue[1]; } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; - TObject g; /* global table for this closure */ + TValue g; /* global table for this closure */ UpVal *upvals[1]; } LClosure; @@ -287,8 +305,8 @@ typedef union Closure { */ typedef struct Node { - TObject i_key; - TObject i_val; + TValue i_key; + TValue i_val; struct Node *next; /* for chaining */ } Node; @@ -298,7 +316,7 @@ typedef struct Table { lu_byte flags; /* 1<<p means tagmethod(p) is not present */ lu_byte lsizenode; /* log2 of size of `node' array */ struct Table *metatable; - TObject *array; /* array part */ + TValue *array; /* array part */ Node *node; Node *firstfree; /* this position is free; all positions after it are full */ GCObject *gclist; @@ -319,13 +337,13 @@ typedef struct Table { -extern const TObject luaO_nilobject; +extern const TValue luaO_nilobject; int luaO_log2 (unsigned int x); int luaO_int2fb (unsigned int x); #define fb2int(x) (((x) & 7) << ((x) >> 3)) -int luaO_rawequalObj (const TObject *t1, const TObject *t2); +int luaO_rawequalObj (const TValue *t1, const TValue *t2); int luaO_str2d (const char *s, lua_Number *result); const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); diff --git a/src/lopcodes.c b/src/lopcodes.c index 993e426d..3ffda71a 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,7 +1,5 @@ /* -** $Id: lopcodes.c,v 1.22 2002/12/04 17:38:31 roberto Exp $ -** extracted automatically from lopcodes.h by mkprint.lua -** DO NOT EDIT +** $Id: lopcodes.c,v 1.25 2003/05/14 21:09:53 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -14,9 +12,11 @@ #include "lopcodes.h" +/* ORDER OP */ + #ifdef LUA_OPNAMES -const char *const luaP_opnames[] = { +const char *const luaP_opnames[NUM_OPCODES] = { "MOVE", "LOADK", "LOADBOOL", @@ -46,6 +46,7 @@ const char *const luaP_opnames[] = { "TAILCALL", "RETURN", "FORLOOP", + "FORPREP", "TFORLOOP", "TFORPREP", "SETLIST", @@ -56,47 +57,45 @@ const char *const luaP_opnames[] = { #endif -#define opmode(t,b,bk,ck,sa,k,m) (((t)<<OpModeT) | \ - ((b)<<OpModeBreg) | ((bk)<<OpModeBrk) | ((ck)<<OpModeCrk) | \ - ((sa)<<OpModesetA) | ((k)<<OpModeK) | (m)) - +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) const lu_byte luaP_opmodes[NUM_OPCODES] = { -/* T B Bk Ck sA K mode opcode */ - opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_MOVE */ - ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_LOADK */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_LOADNIL */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_GETUPVAL */ - ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_GETGLOBAL */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, 0, 0, 0, 1, iABx) /* OP_SETGLOBAL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */ - ,opmode(0, 0, 1, 1, 0, 0, iABC) /* OP_SETTABLE */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_SELF */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_ADD */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_SUB */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_MUL */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_DIV */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_POW */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_UNM */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_NOT */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_CONCAT */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_JMP */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_EQ */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LT */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LE */ - ,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TEST */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CALL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_TAILCALL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_RETURN */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_FORLOOP */ - ,opmode(1, 0, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_TFORPREP */ - ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLIST */ - ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLISTO */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CLOSE */ - ,opmode(0, 0, 0, 0, 1, 0, iABx) /* OP_CLOSURE */ +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,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, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_TFORPREP */ + ,opmode(0, 0, OpArgU, OpArgN, iABx) /* OP_SETLIST */ + ,opmode(0, 0, OpArgU, OpArgN, iABx) /* OP_SETLISTO */ + ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ }; diff --git a/src/lopcodes.h b/src/lopcodes.h index 0b6b58f3..28df697d 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.102 2002/08/21 18:56:09 roberto Exp $ +** $Id: lopcodes.h,v 1.106 2003/05/15 19:46:03 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -134,7 +134,7 @@ name args description ------------------------------------------------------------------------*/ OP_MOVE,/* A B R(A) := R(B) */ OP_LOADK,/* A Bx R(A) := Kst(Bx) */ -OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) PC++ */ +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] */ @@ -159,7 +159,7 @@ OP_NOT,/* A B R(A) := not R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ -OP_JMP,/* sBx PC += sBx */ +OP_JMP,/* sBx pc+=sBx */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ @@ -171,12 +171,13 @@ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ -OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then PC+= sBx */ +OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then pc+=sBx */ +OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ OP_TFORLOOP,/* A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); if R(A+2) ~= nil then pc++ */ OP_TFORPREP,/* A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next; - PC += sBx */ + pc+=sBx */ OP_SETLIST,/* A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1 */ OP_SETLISTO,/* A Bx */ @@ -205,29 +206,31 @@ OP_CLOSURE/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ /* -** masks for instruction properties +** masks for instruction properties. The format is: +** bits 0-1: op mode +** bits 2-3: C arg mode +** bits 4-5: B arg mode +** bit 6: instruction set register A +** bit 7: operator is a test */ -enum OpModeMask { - OpModeBreg = 2, /* B is a register */ - OpModeBrk, /* B is a register/constant */ - OpModeCrk, /* C is a register/constant */ - OpModesetA, /* instruction set register A */ - OpModeK, /* Bx is a constant */ - OpModeT /* operator is a test */ - -}; +enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ +}; extern const lu_byte luaP_opmodes[NUM_OPCODES]; -#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) -#define testOpMode(m, b) (luaP_opmodes[m] & (1 << (b))) +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) +#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) -#ifdef LUA_OPNAMES -extern const char *const luaP_opnames[]; /* opcode names */ -#endif - +extern const char *const luaP_opnames[NUM_OPCODES]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ diff --git a/src/lparser.c b/src/lparser.c index 99bd3020..a8dafb6f 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.208a 2003/04/03 13:35:34 roberto Exp $ +** $Id: lparser.c,v 2.2 2004/03/12 19:53:56 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -13,6 +13,7 @@ #include "lcode.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" @@ -27,9 +28,10 @@ #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) luaY_errorlimit(fs,l,m) -#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ - luaX_syntaxerror(ls, "too many syntax levels"); +#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ + luaX_lexerror(ls, "chunk has too many syntax levels", 0) #define leavelevel(ls) ((ls)->nestlevel--) @@ -39,9 +41,9 @@ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ int breaklist; /* list of jumps out of this loop */ - int nactvar; /* # active local variables outside the breakable structure */ - int upval; /* true if some variable in the block is an upvalue */ - int isbreakable; /* true if `block' is a loop */ + lu_byte nactvar; /* # active locals outside the breakable structure */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isbreakable; /* true if `block' is a loop */ } BlockCnt; @@ -71,12 +73,29 @@ static void lookahead (LexState *ls) { } +static void anchor_token (LexState *ls) { + if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { + TString *ts = ls->t.seminfo.ts; + luaX_newstring(ls, getstr(ts), ts->tsv.len); + } +} + + static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token))); } +static void luaY_errorlimit (FuncState *fs, int limit, const char *what) { + const char *msg = (fs->f->lineDefined == 0) ? + luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : + luaO_pushfstring(fs->L, "function at line %d has more than %d %s", + fs->f->lineDefined, limit, what); + luaX_lexerror(fs->ls, msg, 0); +} + + static int testnext (LexState *ls, int c) { if (ls->t.token == c) { next(ls); @@ -138,17 +157,25 @@ static void checkname(LexState *ls, expdesc *e) { static int luaI_registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; + int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, MAX_INT, ""); + LocVar, USHRT_MAX, "too many local variables"); + while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } +#define new_localvarliteral(ls,v,n) \ + new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) + + static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; - luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name); + luaY_checklimit(fs, fs->nactvar+n+1, MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = cast(unsigned short, + luaI_registerlocalvar(ls, name)); } @@ -168,32 +195,26 @@ static void removevars (LexState *ls, int tolevel) { } -static void new_localvarstr (LexState *ls, const char *name, int n) { - new_localvar(ls, luaS_new(ls->L, name), n); -} - - -static void create_local (LexState *ls, const char *name) { - new_localvarstr(ls, name, 0); - adjustlocalvars(ls, 1); -} - - static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; + int oldsize = f->sizeupvalues; for (i=0; i<f->nups; i++) { if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) { - lua_assert(fs->f->upvalues[i] == name); + lua_assert(f->upvalues[i] == name); return i; } } /* new one */ - luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues"); - luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues, + luaY_checklimit(fs, f->nups + 1, MAXUPVALUES, "upvalues"); + luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, TString *, MAX_INT, ""); - fs->f->upvalues[f->nups] = name; - fs->upvalues[f->nups] = *v; + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; + f->upvalues[f->nups] = name; + luaC_objbarrier(fs->L, f, name); + lua_assert(v->k == VLOCAL || v->k == VUPVAL); + fs->upvalues[f->nups].k = cast(lu_byte, v->k); + fs->upvalues[f->nups].info = cast(lu_byte, v->info); return f->nups++; } @@ -267,18 +288,6 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { } -static void code_params (LexState *ls, int nparams, int dots) { - FuncState *fs = ls->fs; - adjustlocalvars(ls, nparams); - luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters"); - fs->f->numparams = cast(lu_byte, fs->nactvar); - fs->f->is_vararg = cast(lu_byte, dots); - if (dots) - create_local(ls, "arg"); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ -} - - static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; @@ -305,10 +314,13 @@ static void leaveblock (FuncState *fs) { static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { FuncState *fs = ls->fs; Proto *f = fs->f; + int oldsize = f->sizep; int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = func->f; + luaC_objbarrier(ls->L, f, func->f); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); for (i=0; i<func->f->nups; i++) { OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; @@ -318,24 +330,30 @@ static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { static void open_func (LexState *ls, FuncState *fs) { - Proto *f = luaF_newproto(ls->L); + lua_State *L = ls->L; + Proto *f = luaF_newproto(L); fs->f = f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; - fs->L = ls->L; + fs->L = L; ls->fs = fs; fs->pc = 0; fs->lasttarget = 0; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; - fs->h = luaH_new(ls->L, 0, 0); fs->np = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->bl = NULL; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L, 0, 0); + /* anchor table of constants and prototype (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); + setptvalue2s(L, L->top, f); + incr_top(L); } @@ -349,7 +367,7 @@ static void close_func (LexState *ls) { f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject); + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; @@ -360,15 +378,18 @@ static void close_func (LexState *ls) { lua_assert(luaG_checkcode(f)); lua_assert(fs->bl == NULL); ls->fs = fs->prev; + L->top -= 2; /* remove table and prototype from the stack */ + /* last token read was anchored in defunct function; must reanchor it */ + if (fs) anchor_token(ls); } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; lexstate.nestlevel = 0; - luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); + luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); next(&lexstate); /* read first token */ chunk(&lexstate); @@ -377,6 +398,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.nestlevel == 0); + lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -429,7 +451,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { int reg = ls->fs->freereg; expdesc key, val; if (ls->t.token == TK_NAME) { - luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); + luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); cc->nh++; checkname(ls, &key); } @@ -473,7 +495,7 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); - luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor"); + luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor"); cc->na++; cc->tostore++; } @@ -527,18 +549,35 @@ static void constructor (LexState *ls, expdesc *t) { static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; int nparams = 0; - int dots = 0; + f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { - case TK_DOTS: dots = 1; next(ls); break; - case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; + case TK_NAME: { /* param -> NAME [ `=' `...' ] */ + new_localvar(ls, str_checkname(ls), nparams++); + if (testnext(ls, '=')) { + check(ls, TK_DOTS); + f->is_vararg = 1; + } + break; + } + case TK_DOTS: { /* param -> `...' */ + next(ls); + /* use `arg' as default name */ + new_localvarliteral(ls, "arg", nparams++); + f->is_vararg = 1; + break; + } default: luaX_syntaxerror(ls, "<name> or `...' expected"); } - } while (!dots && testnext(ls, ',')); + } while (!f->is_vararg && testnext(ls, ',')); } - code_params(ls, nparams, dots); + adjustlocalvars(ls, nparams); + f->numparams = fs->nactvar - f->is_vararg; + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -548,8 +587,10 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { open_func(ls, &new_fs); new_fs.f->lineDefined = line; check(ls, '('); - if (needself) - create_local(ls, "self"); + if (needself) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } parlist(ls); check(ls, ')'); chunk(ls); @@ -645,18 +686,6 @@ static void prefixexp (LexState *ls, expdesc *v) { singlevar(ls, v, 1); return; } -#ifdef LUA_COMPATUPSYNTAX - case '%': { /* for compatibility only */ - TString *varname; - int line = ls->linenumber; - next(ls); /* skip `%' */ - varname = singlevar(ls, v, 1); - if (v->k != VUPVAL) - luaX_errorline(ls, "global upvalues are obsolete", - getstr(varname), line); - return; - } -#endif default: { luaX_syntaxerror(ls, "unexpected symbol"); return; @@ -796,7 +825,7 @@ static const struct { ** subexpr -> (simplexep | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ -static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { +static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); @@ -809,13 +838,13 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) { + while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, cast(int, priority[op].right)); + nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } @@ -825,7 +854,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, -1); + subexpr(ls, v, 0); } /* }==================================================================== */ @@ -931,12 +960,14 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { } -static void cond (LexState *ls, expdesc *v) { +static int cond (LexState *ls) { /* cond -> exp */ - expr(ls, v); /* read condition */ - if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */ - luaK_goiftrue(ls->fs, v); - luaK_patchtohere(ls->fs, v->t); + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + luaK_patchtohere(ls->fs, v.t); + return v.f; } @@ -1004,14 +1035,14 @@ static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); - expdesc v; + int flist; BlockCnt bl; enterblock(fs, &bl, 1); next(ls); block(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); - cond(ls, &v); - luaK_patchlist(fs, v.f, repeat_init); + flist = cond(ls); + luaK_patchlist(fs, flist, repeat_init); leaveblock(fs); } @@ -1027,30 +1058,34 @@ static int exp1 (LexState *ls) { static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; - adjustlocalvars(ls, nvars); /* scope for all variables */ + adjustlocalvars(ls, 3); /* control variables */ check(ls, TK_DO); - enterblock(fs, &bl, 1); /* loop block */ - prep = luaK_getlabel(fs); + prep = luaK_codeAsBx(fs, (isnum ? OP_FORPREP : OP_TFORPREP), base, NO_JUMP); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); block(ls); - luaK_patchtohere(fs, prep-1); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); - leaveblock(fs); + luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); } static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] DO body */ + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; - new_localvar(ls, varname, 0); - new_localvarstr(ls, "(for limit)", 1); - new_localvarstr(ls, "(for step)", 2); + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); check(ls, '='); exp1(ls); /* initial value */ check(ls, ','); @@ -1061,39 +1096,39 @@ static void fornum (LexState *ls, TString *varname, int line) { luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } - luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); - luaK_jump(fs); - forbody(ls, base, line, 3, 1); + forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist1 DO body */ + /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 0; int line; int base = fs->freereg; - new_localvarstr(ls, "(for generator)", nvars++); - new_localvarstr(ls, "(for state)", nvars++); + /* create control variables */ + new_localvarliteral(ls, "(for generator)", nvars++); + new_localvarliteral(ls, "(for state)", nvars++); + new_localvarliteral(ls, "(for control)", nvars++); + /* create declared variables */ new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); check(ls, TK_IN); line = ls->linenumber; - adjust_assign(ls, nvars, explist1(ls, &e), &e); + adjust_assign(ls, 3, explist1(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ - luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); - forbody(ls, base, line, nvars, 0); + forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { - /* forstat -> fornum | forlist */ + /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; - enterblock(fs, &bl, 0); /* block to control variable scope */ + enterblock(fs, &bl, 1); /* scope for loop and control variables */ next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { @@ -1102,38 +1137,40 @@ static void forstat (LexState *ls, int line) { default: luaX_syntaxerror(ls, "`=' or `in' expected"); } check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ } -static void test_then_block (LexState *ls, expdesc *v) { +static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ + int flist; next(ls); /* skip IF or ELSEIF */ - cond(ls, v); + flist = cond(ls); check(ls, TK_THEN); block(ls); /* `then' part */ + return flist; } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; - expdesc v; + int flist; int escapelist = NO_JUMP; - test_then_block(ls, &v); /* IF cond THEN block */ + flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); - test_then_block(ls, &v); /* ELSEIF cond THEN block */ + luaK_patchtohere(fs, flist); + flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); + luaK_patchtohere(fs, flist); next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else - luaK_concat(fs, &escapelist, v.f); + luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } @@ -1324,7 +1361,8 @@ static void chunk (LexState *ls) { while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); testnext(ls, ';'); - lua_assert(ls->fs->freereg >= ls->fs->nactvar); + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ } leavelevel(ls); diff --git a/src/lparser.h b/src/lparser.h index d6aaaf0e..b4652040 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.47 2003/02/11 10:46:24 roberto Exp $ +** $Id: lparser.h,v 1.50 2003/08/25 19:51:54 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -41,6 +41,12 @@ typedef struct expdesc { } expdesc; +typedef struct upvaldesc { + lu_byte k; + lu_byte info; +} upvaldesc; + + struct BlockCnt; /* defined in lparser.c */ @@ -59,13 +65,13 @@ typedef struct FuncState { int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ int nlocvars; /* number of elements in `locvars' */ - int nactvar; /* number of active local variables */ - expdesc upvalues[MAXUPVALUES]; /* upvalues */ - int actvar[MAXVARS]; /* declared-variable stack */ + lu_byte nactvar; /* number of active local variables */ + upvaldesc upvalues[MAXUPVALUES]; /* upvalues */ + unsigned short actvar[MAXVARS]; /* declared-variable stack */ } FuncState; -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff); +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name); #endif diff --git a/src/lstate.c b/src/lstate.c index b593658d..d1494b58 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,11 +1,11 @@ /* -** $Id: lstate.c,v 1.123 2003/04/03 13:35:34 roberto Exp $ +** $Id: lstate.c,v 2.5 2004/03/23 12:57:12 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ -#include <stdlib.h> +#include <stddef.h> #define lstate_c @@ -34,41 +34,28 @@ union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; #endif +#define state_size(x) (sizeof(x) + EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + EXTRASPACE)) +#define fromstate(l) (cast(lu_byte *, (l)) - EXTRASPACE) + /* -** you can change this function through the official API: -** call `lua_setpanicf' +** Main thread combines a thread state and the global state */ -static int default_panic (lua_State *L) { - UNUSED(L); - return 0; -} - - -static lua_State *mallocstate (lua_State *L) { - lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE); - if (block == NULL) return NULL; - else { - block += EXTRASPACE; - return cast(lua_State *, block); - } -} - - -static void freestate (lua_State *L, lua_State *L1) { - luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE, - sizeof(lua_State) + EXTRASPACE); -} +typedef struct LG { + lua_State l; + global_State g; +} LG; + static void stack_init (lua_State *L1, lua_State *L) { - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject); + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); L1->ci = L1->base_ci; - L1->ci->state = CI_C; /* not a Lua function */ setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; @@ -79,7 +66,7 @@ static void stack_init (lua_State *L1, lua_State *L) { static void freestack (lua_State *L, lua_State *L1) { luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); - luaM_freearray(L, L1->stack, L1->stacksize, TObject); + luaM_freearray(L, L1->stack, L1->stacksize, TValue); } @@ -87,54 +74,42 @@ static void freestack (lua_State *L, lua_State *L1) { ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { - /* create a new global state */ - global_State *g = luaM_new(NULL, global_State); + Udata *u; /* head of udata list */ UNUSED(ud); - if (g == NULL) luaD_throw(L, LUA_ERRMEM); - L->l_G = g; - g->mainthread = L; - g->GCthreshold = 0; /* mark it as unfinished state */ - g->strt.size = 0; - g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(defaultmeta(L)); - setnilvalue(registry(L)); - luaZ_initbuffer(L, &g->buff); - g->panic = default_panic; - g->rootgc = NULL; - g->rootudata = NULL; - g->tmudata = NULL; - setnilvalue(gkey(g->dummynode)); - setnilvalue(gval(g->dummynode)); - g->dummynode->next = NULL; - g->nblocks = sizeof(lua_State) + sizeof(global_State); + u = cast(Udata *, luaM_malloc(L, sizeudata(0))); + u->uv.len = 0; + u->uv.metatable = NULL; + G(L)->firstudata = obj2gco(u); + luaC_link(L, obj2gco(u), LUA_TUSERDATA); + setbit(u->uv.marked, FIXEDBIT); + setbit(L->marked, FIXEDBIT); stack_init(L, L); /* init stack */ - /* create default meta table with a dummy table, and then close the loop */ - defaultmeta(L)->tt = LUA_TTABLE; - sethvalue(defaultmeta(L), luaH_new(L, 0, 0)); - hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L)); - sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ - sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */ + sethvalue(L, gt(L), luaH_new(L, 0, 4)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 4, 4)); /* registry */ 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(L)->nblocks; + G(L)->GCthreshold = 4*G(L)->nblocks; } -static void preinit_state (lua_State *L) { +static void preinit_state (lua_State *L, global_State *g) { + L->l_G = g; + L->tt = LUA_TTHREAD; + L->marked = luaC_white(g); L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; - L->hookmask = L->hookinit = 0; + L->hookmask = 0; L->basehookcount = 0; L->allowhook = 1; resethookcount(L); L->openupval = NULL; L->size_ci = 0; L->nCcalls = 0; + L->isSuspended = 0; L->base_ci = L->ci = NULL; L->errfunc = 0; setnilvalue(gt(L)); @@ -142,30 +117,26 @@ static void preinit_state (lua_State *L) { static void close_state (lua_State *L) { + global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - if (G(L)) { /* close global state */ - luaC_sweep(L, 1); /* collect all elements */ - lua_assert(G(L)->rootgc == NULL); - lua_assert(G(L)->rootudata == NULL); - luaS_freeall(L); - luaZ_freebuffer(L, &G(L)->buff); - } + luaC_sweepall(L); /* collect all elements */ + lua_assert(g->rootgc == obj2gco(L)); + luaS_freeall(L); + luaZ_freebuffer(L, &g->buff); freestack(L, L); - if (G(L)) { - lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State)); - luaM_freelem(NULL, G(L)); - } - freestate(NULL, L); + lua_assert(g->nblocks == sizeof(LG)); + (*g->realloc)(g->ud, fromstate(L), state_size(LG), 0); } lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = mallocstate(L); - luaC_link(L, valtogco(L1), LUA_TTHREAD); - preinit_state(L1); - L1->l_G = L->l_G; + lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); + L1->next = L->next; /* link new thread after `L' */ + L->next = obj2gco(L1); + preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ - setobj2n(gt(L1), gt(L)); /* share table of globals */ + setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + lua_assert(iswhite(obj2gco(L1))); return L1; } @@ -174,23 +145,47 @@ void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); freestack(L, L1); - freestate(L, L1); + luaM_free(L, fromstate(L1), state_size(lua_State)); } -LUA_API lua_State *lua_open (void) { - lua_State *L = mallocstate(NULL); - if (L) { /* allocation OK? */ - L->tt = LUA_TTHREAD; - L->marked = 0; - L->next = L->gclist = NULL; - preinit_state(L); - L->l_G = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { - /* memory allocation error: free partial state */ - close_state(L); - L = NULL; - } +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + lua_State *L; + global_State *g; + void *l = (*f)(ud, NULL, 0, state_size(LG)); + if (l == NULL) return NULL; + L = tostate(l); + g = &((LG *)L)->g; + L->next = NULL; + g->currentwhite = bitmask(WHITE0BIT); + preinit_state(L, g); + g->realloc = f; + g->ud = ud; + g->mainthread = L; + g->GCthreshold = 0; /* mark it as unfinished state */ + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->gcstate = GCSfinalize; + g->rootgc = obj2gco(L); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->firstudata = NULL; + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->tmudata = NULL; + setnilvalue(gkey(g->dummynode)); + setnilvalue(gval(g->dummynode)); + g->dummynode->next = NULL; + g->nblocks = sizeof(LG); + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; } lua_userstateopen(L); return L; @@ -207,7 +202,7 @@ LUA_API void lua_close (lua_State *L) { lua_lock(L); L = G(L)->mainthread; /* only the main thread can be closed */ luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L); /* separate udata that have GC metamethods */ + luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; diff --git a/src/lstate.h b/src/lstate.h index 5422f1b1..ab01d169 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.109 2003/02/27 11:52:30 roberto Exp $ +** $Id: lstate.h,v 2.2 2004/03/23 17:02:58 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -42,9 +42,6 @@ struct lua_longjmp; /* defined in ldo.c */ -/* default meta table (both for tables and udata) */ -#define defaultmeta(L) (&G(L)->_defaultmeta) - /* table of globals */ #define gt(L) (&L->_gt) @@ -64,7 +61,7 @@ struct lua_longjmp; /* defined in ldo.c */ typedef struct stringtable { GCObject **hash; - ls_nstr nuse; /* number of elements */ + lu_int32 nuse; /* number of elements */ int size; } stringtable; @@ -75,11 +72,9 @@ typedef struct stringtable { typedef struct CallInfo { StkId base; /* base for called function */ StkId top; /* top for this function */ - int state; /* bit fields; see below */ union { struct { /* for Lua functions */ const Instruction *savedpc; - const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ int tailcalls; /* number of tail calls lost under this entry */ } l; struct { /* for C functions */ @@ -89,20 +84,11 @@ typedef struct CallInfo { } CallInfo; -/* -** bit fields for `CallInfo.state' -*/ -#define CI_C (1<<0) /* 1 if function is a C function */ -/* 1 if (Lua) function has an active `luaV_execute' running it */ -#define CI_HASFRAME (1<<1) -/* 1 if Lua function is calling another Lua function (and therefore its - `pc' is being used by the other, and therefore CI_SAVEDPC is 1 too) */ -#define CI_CALLING (1<<2) -#define CI_SAVEDPC (1<<3) /* 1 if `savedpc' is updated */ -#define CI_YIELD (1<<4) /* 1 if thread is suspended */ - +#define curr_func(L) (clvalue(L->base - 1)) #define ci_func(ci) (clvalue((ci)->base - 1)) +#define f_isLua(ci) (!ci_func(ci)->c.isC) +#define isLua(ci) (ttisfunction((ci)->base - 1) && f_isLua(ci)) /* @@ -110,15 +96,23 @@ typedef struct CallInfo { */ typedef struct global_State { stringtable strt; /* hash table for strings */ - GCObject *rootgc; /* list of (almost) all collectable objects */ - GCObject *rootudata; /* (separated) list of all userdata */ + lua_Alloc realloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to `realloc' */ + int currentwhite; + GCObject *rootgc; /* list of all collectable objects */ + GCObject *firstudata; /* udata go to the end of `rootgc' */ + GCObject **sweepgc; /* position of sweep in `rootgc' */ + int sweepstrgc; /* position of sweep in `strt' */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of weak tables (to be cleared) */ GCObject *tmudata; /* list of userdata to be GC */ + int gcstate; /* state of garbage collector */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem nblocks; /* number of `bytes' currently allocated */ lua_CFunction panic; /* to be called in unprotected errors */ - TObject _registry; - TObject _defaultmeta; + TValue _registry; struct lua_State *mainthread; Node dummynode[1]; /* common node array for all empty tables */ TString *tmname[TM_N]; /* array with tag-method names */ @@ -143,11 +137,11 @@ struct lua_State { unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; - lu_byte hookinit; + lu_byte isSuspended; int basehookcount; int hookcount; lua_Hook hook; - TObject _gt; /* table of globals */ + TValue _gt; /* table of globals */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ @@ -174,18 +168,20 @@ union GCObject { /* macros to convert a GCObject into a specific value */ -#define gcotots(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) -#define gcotou(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) -#define gcotocl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) -#define gcotoh(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) -#define gcotop(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) -#define gcotouv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define gco2ts(o) (&rawgco2ts(o)->tsv) +#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) +#define gco2u(o) (&rawgco2u(o)->uv) +#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) +#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define ngcotouv(o) \ check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) -#define gcototh(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) +#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) -/* macro to convert any value into a GCObject */ -#define valtogco(v) (cast(GCObject *, (v))) +/* macro to convert any Lua object into a GCObject */ +#define obj2gco(v) (cast(GCObject *, (v))) lua_State *luaE_newthread (lua_State *L); diff --git a/src/lstring.c b/src/lstring.c index 8cbddbd2..9a26cf03 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.78 2002/12/04 17:38:31 roberto Exp $ +** $Id: lstring.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -25,16 +25,19 @@ void luaS_freeall (lua_State *L) { void luaS_resize (lua_State *L, int newsize) { - GCObject **newhash = luaM_newvector(L, newsize, GCObject *); - stringtable *tb = &G(L)->strt; + GCObject **newhash; + stringtable *tb; int i; + if (G(L)->sweepstrgc > 0) return; /* cannot resize during GC traverse */ + newhash = luaM_newvector(L, newsize, GCObject *); + tb = &G(L)->strt; for (i=0; i<newsize; i++) newhash[i] = NULL; /* rehash */ for (i=0; i<tb->size; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ - lu_hash h = gcotots(p)->tsv.hash; + unsigned int h = gco2ts(p)->hash; int h1 = lmod(h, newsize); /* new position */ lua_assert(cast(int, h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ @@ -48,12 +51,13 @@ void luaS_resize (lua_State *L, int newsize) { } -static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { +static TString *newlstr (lua_State *L, const char *str, size_t l, + unsigned int h) { TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); stringtable *tb; ts->tsv.len = l; ts->tsv.hash = h; - ts->tsv.marked = 0; + ts->tsv.marked = luaC_white(G(L)); ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); @@ -61,9 +65,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { tb = &G(L)->strt; h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = valtogco(ts); + tb->hash[h] = obj2gco(ts); tb->nuse++; - if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2) + if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ return ts; } @@ -71,7 +75,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { GCObject *o; - lu_hash h = (lu_hash)l; /* seed */ + unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ @@ -79,9 +83,12 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { - TString *ts = gcotots(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) + TString *ts = rawgco2ts(o); + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + /* string may be dead */ + if (isdead(G(L), o)) changewhite(o); return ts; + } } return newlstr(L, str, l, h); /* not found */ } @@ -90,13 +97,13 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { Udata *luaS_newudata (lua_State *L, size_t s) { Udata *u; u = cast(Udata *, luaM_malloc(L, sizeudata(s))); - u->uv.marked = (1<<1); /* is not finalized */ + u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; - u->uv.metatable = hvalue(defaultmeta(L)); + u->uv.metatable = NULL; /* chain it on udata list */ - u->uv.next = G(L)->rootudata; - G(L)->rootudata = valtogco(u); + u->uv.next = G(L)->firstudata->uv.next; + G(L)->firstudata->uv.next = obj2gco(u); return u; } diff --git a/src/lstring.h b/src/lstring.h index be5a1e37..2ca352c4 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.37 2002/08/16 14:45:55 roberto Exp $ +** $Id: lstring.h,v 1.38 2003/11/17 19:50:05 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -8,11 +8,11 @@ #define lstring_h +#include "lgc.h" #include "lobject.h" #include "lstate.h" - #define sizestring(l) (cast(lu_mem, sizeof(union TString))+ \ (cast(lu_mem, l)+1)*sizeof(char)) @@ -22,7 +22,7 @@ #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s) ((s)->tsv.marked |= (1<<4)) +#define luaS_fix(s) setbit((s)->tsv.marked, FIXEDBIT) void luaS_resize (lua_State *L, int newsize); Udata *luaS_newudata (lua_State *L, size_t s); diff --git a/src/ltable.c b/src/ltable.c index 0c64adb1..9fc508ba 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 1.132 2003/04/03 13:35:34 roberto Exp $ +** $Id: ltable.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,10 +15,7 @@ ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. -** In other words, there are collisions only when two elements have the -** same main position (i.e. the same hash values for that table size). -** Because of that, the load factor of these tables can be 100% without -** performance penalties. +** Hence even when the load factor reaches 100%, performance remains good. */ #include <string.h> @@ -45,9 +42,7 @@ #define MAXBITS (BITS_INT-2) #endif -/* check whether `x' < 2^MAXBITS */ -#define toobig(x) ((((x)-1) >> MAXBITS) != 0) - +#define MAXASIZE (1 << MAXBITS) /* function to convert a lua_Number to int (with any rounding method) */ #ifndef lua_number2int @@ -87,7 +82,7 @@ static Node *hashnum (const Table *t, lua_Number n) { lua_assert(sizeof(a) <= sizeof(n)); memcpy(a, &n, sizeof(a)); for (i = 1; i < numints; i++) a[0] += a[i]; - return hashmod(t, cast(lu_hash, a[0])); + return hashmod(t, a[0]); } @@ -96,12 +91,12 @@ static Node *hashnum (const Table *t, lua_Number n) { ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ -Node *luaH_mainposition (const Table *t, const TObject *key) { +Node *luaH_mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); case LUA_TSTRING: - return hashstr(t, tsvalue(key)); + return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: @@ -116,11 +111,13 @@ Node *luaH_mainposition (const Table *t, const TObject *key) { ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ -static int arrayindex (const TObject *key) { +static int arrayindex (const TValue *key, lua_Number lim) { if (ttisnumber(key)) { + lua_Number n = nvalue(key); int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k)) + if (n <= 0 || n > lim) return -1; /* out of range? */ + lua_number2int(k, n); + if (cast(lua_Number, k) == nvalue(key)) return k; } return -1; /* `key' did not match some condition */ @@ -135,12 +132,12 @@ static int arrayindex (const TObject *key) { static int luaH_index (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ - i = arrayindex(key); - if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */ + i = arrayindex(key, t->sizearray); + if (0 <= i) { /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ } else { - const TObject *v = luaH_get(t, key); + const TValue *v = luaH_get(t, key); if (v == &luaO_nilobject) luaG_runerror(L, "invalid key for `next'"); i = cast(int, (cast(const lu_byte *, v) - @@ -155,14 +152,14 @@ int luaH_next (lua_State *L, Table *t, StkId key) { for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setnvalue(key, cast(lua_Number, i+1)); - setobj2s(key+1, &t->array[i]); + setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(key, gkey(gnode(t, i))); - setobj2s(key+1, gval(gnode(t, i))); + setobj2s(L, key, gkey(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } @@ -202,6 +199,7 @@ static void numuse (const Table *t, int *narray, int *nhash) { int nums[MAXBITS+1]; int i, lg; int totaluse = 0; + lua_Number sizelimit; /* an upper bound for the array size */ /* count elements in array part */ for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ int ttlg = twoto(lg); /* 2^lg */ @@ -221,10 +219,13 @@ static void numuse (const Table *t, int *narray, int *nhash) { *narray = totaluse; /* all previous uses were in array part */ /* count elements in hash part */ i = sizenode(t); + /* array part cannot be larger than twice the maximum number of elements */ + sizelimit = cast(lua_Number, totaluse + i) * 2; + if (sizelimit >= MAXASIZE) sizelimit = MAXASIZE; while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { - int k = arrayindex(gkey(n)); + int k = arrayindex(gkey(n), sizelimit); if (k >= 0) { /* is `key' an appropriate array index? */ nums[luaO_log2(k-1)+1]++; /* count as such */ (*narray)++; @@ -238,7 +239,7 @@ static void numuse (const Table *t, int *narray, int *nhash) { static void setarrayvector (lua_State *L, Table *t, int size) { int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TObject); + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; i<size; i++) setnilvalue(&t->array[i]); t->sizearray = size; @@ -295,16 +296,16 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { /* re-insert elements from vanishing slice */ for (i=nasize; i<oldasize; i++) { if (!ttisnil(&t->array[i])) - setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]); + setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); } /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TObject); + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements in hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) - setobjt2t(luaH_set(L, t, gkey(old)), gval(old)); + setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); } if (oldhsize) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ @@ -326,8 +327,8 @@ static void rehash (lua_State *L, Table *t) { Table *luaH_new (lua_State *L, int narray, int lnhash) { Table *t = luaM_new(L, Table); - luaC_link(L, valtogco(t), LUA_TTABLE); - t->metatable = hvalue(defaultmeta(L)); + luaC_link(L, obj2gco(t), LUA_TTABLE); + t->metatable = NULL; t->flags = cast(lu_byte, ~0); /* temporary values (kept only if some malloc fails) */ t->array = NULL; @@ -343,7 +344,7 @@ Table *luaH_new (lua_State *L, int narray, int lnhash) { void luaH_free (lua_State *L, Table *t) { if (t->lsizenode) luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TObject); + luaM_freearray(L, t->array, t->sizearray, TValue); luaM_freelem(L, t); } @@ -376,8 +377,8 @@ void luaH_remove (Table *t, Node *e) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -static TObject *newkey (lua_State *L, Table *t, const TObject *key) { - TObject *val; +static TValue *newkey (lua_State *L, Table *t, const TValue *key) { + TValue *val; Node *mp = luaH_mainposition(t, key); if (!ttisnil(gval(mp))) { /* main position is not free? */ Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */ @@ -397,7 +398,8 @@ static TObject *newkey (lua_State *L, Table *t, const TObject *key) { mp = n; } } - setobj2t(gkey(mp), key); /* write barrier */ + setobj2t(L, gkey(mp), key); + luaC_barrier(L, t, key); lua_assert(ttisnil(gval(mp))); for (;;) { /* correct `firstfree' */ if (ttisnil(gkey(t->firstfree))) @@ -408,7 +410,7 @@ static TObject *newkey (lua_State *L, Table *t, const TObject *key) { /* no more free places; must create one */ setbvalue(gval(mp), 0); /* avoid new key being removed */ rehash(L, t); /* grow table */ - val = cast(TObject *, luaH_get(t, key)); /* get new position */ + val = cast(TValue *, luaH_get(t, key)); /* get new position */ lua_assert(ttisboolean(val)); setnilvalue(val); return val; @@ -418,23 +420,22 @@ static TObject *newkey (lua_State *L, Table *t, const TObject *key) { /* ** generic search function */ -static const TObject *luaH_getany (Table *t, const TObject *key) { - if (ttisnil(key)) return &luaO_nilobject; - else { +static const TValue *luaH_getany (Table *t, const TValue *key) { + if (!ttisnil(key)) { Node *n = luaH_mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ else n = n->next; } while (n); - return &luaO_nilobject; } + return &luaO_nilobject; } /* ** search function for integers */ -const TObject *luaH_getnum (Table *t, int key) { +const TValue *luaH_getnum (Table *t, int key) { if (1 <= key && key <= t->sizearray) return &t->array[key-1]; else { @@ -453,10 +454,10 @@ const TObject *luaH_getnum (Table *t, int key) { /* ** search function for strings */ -const TObject *luaH_getstr (Table *t, TString *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)) && tsvalue(gkey(n)) == key) + if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) return gval(n); /* that's it */ else n = n->next; } while (n); @@ -467,9 +468,9 @@ const TObject *luaH_getstr (Table *t, TString *key) { /* ** main search function */ -const TObject *luaH_get (Table *t, const TObject *key) { +const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; lua_number2int(k, (nvalue(key))); @@ -482,11 +483,11 @@ const TObject *luaH_get (Table *t, const TObject *key) { } -TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { - const TObject *p = luaH_get(t, key); +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); t->flags = 0; if (p != &luaO_nilobject) - return cast(TObject *, p); + return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); else if (ttisnumber(key) && nvalue(key) != nvalue(key)) @@ -496,14 +497,26 @@ TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { } -TObject *luaH_setnum (lua_State *L, Table *t, int key) { - const TObject *p = luaH_getnum(t, key); +TValue *luaH_setnum (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getnum(t, key); if (p != &luaO_nilobject) - return cast(TObject *, p); + return cast(TValue *, p); else { - TObject k; + TValue k; setnvalue(&k, cast(lua_Number, key)); return newkey(L, t, &k); } } + +TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { + const TValue *p = luaH_getstr(t, key); + if (p != &luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setsvalue(L, &k, key); + return newkey(L, t, &k); + } +} + diff --git a/src/ltable.h b/src/ltable.h index 3d4d753c..566d7cd4 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 1.44 2003/03/18 12:50:04 roberto Exp $ +** $Id: ltable.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,17 +15,18 @@ #define gval(n) (&(n)->i_val) -const TObject *luaH_getnum (Table *t, int key); -TObject *luaH_setnum (lua_State *L, Table *t, int key); -const TObject *luaH_getstr (Table *t, TString *key); -const TObject *luaH_get (Table *t, const TObject *key); -TObject *luaH_set (lua_State *L, Table *t, const TObject *key); +const TValue *luaH_getnum (Table *t, int key); +TValue *luaH_setnum (lua_State *L, Table *t, int key); +const TValue *luaH_getstr (Table *t, TString *key); +TValue *luaH_setstr (lua_State *L, Table *t, TString *key); +const TValue *luaH_get (Table *t, const TValue *key); +TValue *luaH_set (lua_State *L, Table *t, const TValue *key); Table *luaH_new (lua_State *L, int narray, int lnhash); void luaH_free (lua_State *L, Table *t); int luaH_next (lua_State *L, Table *t, StkId key); /* exported only for debugging */ -Node *luaH_mainposition (const Table *t, const TObject *key); +Node *luaH_mainposition (const Table *t, const TValue *key); #endif @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.106 2003/04/03 13:35:34 roberto Exp $ +** $Id: ltm.c,v 2.2 2004/02/16 19:09:52 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -21,7 +21,8 @@ const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata", "thread" + "string", "table", "function", "userdata", "thread", + "proto", "upval" }; @@ -45,8 +46,8 @@ void luaT_init (lua_State *L) { ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ -const TObject *luaT_gettm (Table *events, TMS event, TString *ename) { - const TObject *tm = luaH_getstr(events, ename); +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast(lu_byte, 1u<<event); /* cache this fact */ @@ -56,15 +57,18 @@ const TObject *luaT_gettm (Table *events, TMS event, TString *ename) { } -const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event) { - TString *ename = G(L)->tmname[event]; +const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { + Table *mt; switch (ttype(o)) { case LUA_TTABLE: - return luaH_getstr(hvalue(o)->metatable, ename); + mt = hvalue(o)->metatable; + break; case LUA_TUSERDATA: - return luaH_getstr(uvalue(o)->uv.metatable, ename); + mt = uvalue(o)->metatable; + break; default: - return &luaO_nilobject; + mt = NULL; } + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : &luaO_nilobject); } @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 1.41 2002/11/14 11:51:50 roberto Exp $ +** $Id: ltm.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -36,14 +36,14 @@ typedef enum { -#define gfasttm(g,et,e) \ - (((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) #define fasttm(l,et,e) gfasttm(G(l), et, e) -const TObject *luaT_gettm (Table *events, TMS event, TString *ename); -const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event); +const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); void luaT_init (lua_State *L); extern const char *const luaT_typenames[]; diff --git a/src/lua/RCS b/src/lua/RCS new file mode 120000 index 00000000..1ae38936 --- /dev/null +++ b/src/lua/RCS @@ -0,0 +1 @@ +../RCS
\ No newline at end of file diff --git a/src/lua/README b/src/lua/README index febd229a..fca1e900 100644 --- a/src/lua/README +++ b/src/lua/README @@ -2,7 +2,7 @@ This is lua, a sample Lua interpreter. It can be used as a batch interpreter and also interactively. There are man pages for it in both nroff and html in ../../doc. -Usage: ./lua [options] [script [args]]. Available options are: +Usage: lua [options] [script [args]]. Available options are: - execute stdin as a file -e stat execute string `stat' -i enter interactive mode after executing `script' diff --git a/src/lua/lua.c b/src/lua/lua.c index 28c84cb6..4e669c07 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.122 2003/04/03 13:34:42 roberto Exp $ +** $Id: lua.c,v 1.124 2003/10/23 18:06:22 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -117,10 +117,9 @@ static void l_message (const char *pname, const char *msg) { static int report (int status) { - const char *msg; - if (status) { - msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error with no message)"; + if (status && !lua_isnil(L, -1)) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); } @@ -155,10 +154,6 @@ static void getargs (char *argv[], int n) { lua_pushstring(L, argv[i]); lua_rawset(L, -3); } - /* arg.n = maximum index in table `arg' */ - lua_pushliteral(L, "n"); - lua_pushnumber(L, i-n-1); - lua_rawset(L, -3); } diff --git a/src/luac/Makefile b/src/luac/Makefile index 9e772b41..a6c7d38f 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -12,8 +12,8 @@ T= $(BIN)/luac all: $T -$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) +$T: $(OBJS) $(LIB)/liblua.a ../lib/lauxlib.o + $(CC) -o $@ $(MYLDFLAGS) $(OBJS) ../lib/lauxlib.o -L$(LIB) -llua $(EXTRA_LIBS) # print.c needs opcode names from lopcodes.c lopcodes.o: ../lopcodes.c ../lopcodes.h @@ -22,8 +22,8 @@ lopcodes.o: ../lopcodes.c ../lopcodes.h $(LIB)/liblua.a: cd ..; $(MAKE) -$(LIB)/liblualib.a: - cd ../lib; $(MAKE) +../lib/lauxlib.o: + cd ../lib; $(MAKE) lauxlib.o clean: rm -f $(OBJS) $T diff --git a/src/luac/RCS b/src/luac/RCS new file mode 120000 index 00000000..1ae38936 --- /dev/null +++ b/src/luac/RCS @@ -0,0 +1 @@ +../RCS
\ No newline at end of file diff --git a/src/luac/README b/src/luac/README index ada7bc4b..140d9457 100644 --- a/src/luac/README +++ b/src/luac/README @@ -6,7 +6,7 @@ The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, and off-line syntax error detection. luac can also be used to learn about the Lua virtual machine. -Usage: /l/luac/luac [options] [filenames]. Available options are: +Usage: luac [options] [filenames]. Available options are: - process stdin -l list -o name output to file `name' (default is "luac.out") diff --git a/src/luac/luac.c b/src/luac/luac.c index 1aff0bd9..f634d5f9 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,9 +1,10 @@ /* -** $Id: luac.c,v 1.44a 2003/04/07 20:34:20 lhf Exp $ +** $Id: luac.c,v 1.47 2004/03/24 00:25:08 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -11,6 +12,7 @@ #include "lua.h" #include "lauxlib.h" +#include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" @@ -18,21 +20,19 @@ #include "lstring.h" #include "lundump.h" -#ifndef LUA_DEBUG -#define luaB_opentests(L) -#endif - #ifndef PROGNAME -#define PROGNAME "luac" /* program name */ +#define PROGNAME "luac" /* default program name */ #endif +#ifndef OUTPUT #define OUTPUT "luac.out" /* default output file */ +#endif static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ static char Output[]={ OUTPUT }; /* default output file name */ -static const char* output=Output; /* output file name */ +static const char* output=Output; /* actual output file name */ static const char* progname=PROGNAME; /* actual program name */ static void fatal(const char* message) @@ -41,29 +41,30 @@ static void fatal(const char* message) exit(EXIT_FAILURE); } -static void cannot(const char* name, const char* what, const char* mode) +static void cannot(const char* what) { - fprintf(stderr,"%s: cannot %s %sput file ",progname,what,mode); - perror(name); + fprintf(stderr,"%s: cannot %s output file %s: %s\n", + progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } -static void usage(const char* message, const char* arg) +static void usage(const char* message) { - if (message!=NULL) - { - fprintf(stderr,"%s: ",progname); fprintf(stderr,message,arg); fprintf(stderr,"\n"); - } + if (*message=='-') + fprintf(stderr,"%s: unrecognized option `%s'\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, - "usage: %s [options] [filenames]. Available options are:\n" + "usage: %s [options] [filenames].\n" + "Available options are:\n" " - process stdin\n" " -l list\n" - " -o name output to file `name' (default is \"" OUTPUT "\")\n" + " -o name output to file `name' (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n", - progname); + progname,Output); exit(EXIT_FAILURE); } @@ -89,7 +90,7 @@ static int doargs(int argc, char* argv[]) else if (IS("-o")) /* output file */ { output=argv[++i]; - if (output==NULL || *output==0) usage("`-o' needs argument",NULL); + if (output==NULL || *output==0) usage("`-o' needs argument"); } else if (IS("-p")) /* parse only */ dumping=0; @@ -101,7 +102,7 @@ static int doargs(int argc, char* argv[]) if (argc==2) exit(EXIT_SUCCESS); } else /* unknown option */ - usage("unrecognized option `%s'",argv[i]); + usage(argv[i]); } if (i==argc && (listing || !dumping)) { @@ -125,6 +126,7 @@ static Proto* combine(lua_State* L, int n) { int i,pc=0; Proto* f=luaF_newproto(L); + setptvalue2s(L,L->top,f); incr_top(L); f->source=luaS_newliteral(L,"=(" PROGNAME ")"); f->maxstacksize=1; f->p=luaM_newvector(L,n,Proto*); @@ -142,23 +144,17 @@ static Proto* combine(lua_State* L, int n) } } -static void strip(lua_State* L, Proto* f) +static int writer(lua_State* L, const void* p, size_t size, void* u) { - int i,n=f->sizep; - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - f->lineinfo=NULL; f->sizelineinfo=0; - f->locvars=NULL; f->sizelocvars=0; - f->upvalues=NULL; f->sizeupvalues=0; - f->source=luaS_newliteral(L,"=(none)"); - for (i=0; i<n; i++) strip(L,f->p[i]); + UNUSED(L); + return fwrite(p,size,1,(FILE*)u)==1; } -static int writer(lua_State* L, const void* p, size_t size, void* u) +static int panic(lua_State *L) { UNUSED(L); - return fwrite(p,size,1,(FILE*)u)==1; + fatal("not enough memory!"); + return 0; } int main(int argc, char* argv[]) @@ -167,9 +163,11 @@ int main(int argc, char* argv[]) Proto* f; int i=doargs(argc,argv); argc-=i; argv+=i; - if (argc<=0) usage("no input files given",NULL); + if (argc<=0) usage("no input files given"); L=lua_open(); - luaB_opentests(L); + if (L==NULL) fatal("not enough memory for state"); + lua_atpanic(L,panic); + if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i<argc; i++) { const char* filename=IS("-") ? NULL : argv[i]; @@ -180,14 +178,13 @@ int main(int argc, char* argv[]) if (dumping) { FILE* D=fopen(output,"wb"); - if (D==NULL) cannot(output,"open","out"); - if (stripping) strip(L,f); + if (D==NULL) cannot("open"); lua_lock(L); - luaU_dump(L,f,writer,D); + luaU_dump(L,f,writer,D,stripping); lua_unlock(L); - if (ferror(D)) cannot(output,"write","out"); - fclose(D); + if (ferror(D)) cannot("write"); + if (fclose(D)) cannot("close"); } lua_close(L); - return 0; + return EXIT_SUCCESS; } diff --git a/src/luac/print.c b/src/luac/print.c index d0b5efb2..2f9e7d12 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,12 +1,12 @@ /* -** $Id: print.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ +** $Id: print.c,v 1.46 2004/03/24 00:25:08 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ #include <stdio.h> -#if 0 +#if 1 #define DEBUG_PRINT #endif @@ -46,7 +46,7 @@ static void PrintString(const Proto* f, int n) static void PrintConstant(const Proto* f, int i) { - const TObject* o=&f->k[i]; + const TValue* o=&f->k[i]; switch (ttype(o)) { case LUA_TNUMBER: @@ -75,8 +75,8 @@ static void PrintCode(const Proto* f) int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); - int bc=GETARG_Bx(i); - int sbc=GETARG_sBx(i); + int bx=GETARG_Bx(i); + int sbx=GETARG_sBx(i); int line=getline(f,pc); #if 0 printf("%0*lX",Sizeof(i)*2,i); @@ -86,14 +86,24 @@ static void PrintCode(const Proto* f) printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { - case iABC: printf("%d %d %d",a,b,c); break; - case iABx: printf("%d %d",a,bc); break; - case iAsBx: printf("%d %d",a,sbc); break; + case iABC: + printf("%d",a); + if (getBMode(o)!=OpArgN) + { if (b>=MAXSTACK) printf(" #%d",b-MAXSTACK); else printf(" %d",b); } + if (getCMode(o)!=OpArgN) + { if (c>=MAXSTACK) printf(" #%d",c-MAXSTACK); else printf(" %d",c); } + break; + case iABx: + 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; } switch (o) { case OP_LOADK: - printf("\t; "); PrintConstant(f,bc); + printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: @@ -101,7 +111,7 @@ static void PrintCode(const Proto* f) break; case OP_GETGLOBAL: case OP_SETGLOBAL: - printf("\t; %s",svalue(&f->k[bc])); + printf("\t; %s",svalue(&f->k[bx])); break; case OP_GETTABLE: case OP_SELF: @@ -121,16 +131,17 @@ static void PrintCode(const Proto* f) printf("\t; "); if (b>=MAXSTACK) PrintConstant(f,b-MAXSTACK); else printf("-"); printf(" "); - if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); + if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: + case OP_FORPREP: case OP_TFORPREP: - printf("\t; to %d",sbc+pc+2); + printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: - printf("\t; %p",VOID(f->p[bc])); + printf("\t; %p",VOID(f->p[bx])); break; default: break; @@ -187,7 +198,7 @@ static void PrintLocals(const Proto* f) for (i=0; i<n; i++) { printf("\t%d\t%s\t%d\t%d\n", - i,getstr(f->locvars[i].varname),f->locvars[i].startpc,f->locvars[i].endpc); + i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } } diff --git a/src/lundump.c b/src/lundump.c index 151a8507..d79dd898 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,14 +1,18 @@ /* -** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $ +** $Id: lundump.c,v 1.51 2004/03/24 00:25:08 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ +#include <stdarg.h> +#include <stddef.h> + #define lundump_c #include "lua.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lopcodes.h" @@ -26,22 +30,28 @@ typedef struct { const char* name; } LoadState; -static void unexpectedEOZ (LoadState* S) +static void error (LoadState* S, const char* fmt, ...) { - luaG_runerror(S->L,"unexpected end of file in %s",S->name); + const char *msg; + va_list argp; + va_start(argp,fmt); + msg=luaO_pushvfstring(S->L,fmt,argp); + va_end(argp); + luaO_pushfstring(S->L,"%s: %s",S->name,msg); + luaD_throw(S->L,LUA_ERRSYNTAX); } static int ezgetc (LoadState* S) { int c=zgetc(S->Z); - if (c==EOZ) unexpectedEOZ(S); + if (c==EOZ) error(S,"unexpected end of file"); return c; } static void ezread (LoadState* S, void* b, int n) { int r=luaZ_read(S->Z,b,n); - if (r!=0) unexpectedEOZ(S); + if (r!=0) error(S,"unexpected end of file"); } static void LoadBlock (LoadState* S, void* b, size_t size) @@ -77,7 +87,7 @@ static int LoadInt (LoadState* S) { int x; LoadBlock(S,&x,sizeof(x)); - if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name); + if (x<0) error(S,"bad integer"); return x; } @@ -113,7 +123,7 @@ static void LoadCode (LoadState* S, Proto* f) int size=LoadInt(S); f->code=luaM_newvector(S->L,size,Instruction); f->sizecode=size; - LoadVector(S,f->code,size,sizeof(*f->code)); + LoadVector(S,f->code,size,sizeof(Instruction)); } static void LoadLocals (LoadState* S, Proto* f) @@ -122,6 +132,7 @@ static void LoadLocals (LoadState* S, Proto* f) n=LoadInt(S); f->locvars=luaM_newvector(S->L,n,LocVar); f->sizelocvars=n; + for (i=0; i<n; i++) f->locvars[i].varname=NULL; for (i=0; i<n; i++) { f->locvars[i].varname=LoadString(S); @@ -135,18 +146,18 @@ static void LoadLines (LoadState* S, Proto* f) int size=LoadInt(S); f->lineinfo=luaM_newvector(S->L,size,int); f->sizelineinfo=size; - LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo)); + LoadVector(S,f->lineinfo,size,sizeof(int)); } static void LoadUpvalues (LoadState* S, Proto* f) { int i,n; n=LoadInt(S); - if (n!=0 && n!=f->nups) - luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d", - S->name,n,f->nups); + if (n!=0 && n!=f->nups) + error(S,"bad nupvalues (read %d; expected %d)",n,f->nups); f->upvalues=luaM_newvector(S->L,n,TString*); f->sizeupvalues=n; + for (i=0; i<n; i++) f->upvalues[i]=NULL; for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); } @@ -156,11 +167,12 @@ static void LoadConstants (LoadState* S, Proto* f) { int i,n; n=LoadInt(S); - f->k=luaM_newvector(S->L,n,TObject); + f->k=luaM_newvector(S->L,n,TValue); f->sizek=n; + for (i=0; i<n; i++) setnilvalue(&f->k[i]); for (i=0; i<n; i++) { - TObject* o=&f->k[i]; + TValue* o=&f->k[i]; int t=LoadByte(S); switch (t) { @@ -168,25 +180,27 @@ static void LoadConstants (LoadState* S, Proto* f) setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: - setsvalue2n(o,LoadString(S)); + setsvalue2n(S->L,o,LoadString(S)); break; case LUA_TNIL: setnilvalue(o); break; default: - luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name); + error(S,"bad constant type (%d)",t); break; } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; + for (i=0; i<n; i++) f->p[i]=NULL; for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source); } static Proto* LoadFunction (LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); + setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; f->lineDefined=LoadInt(S); f->nups=LoadByte(S); @@ -199,8 +213,9 @@ static Proto* LoadFunction (LoadState* S, TString* p) LoadConstants(S,f); LoadCode(S,f); #ifndef TRUST_BINARIES - if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name); + if (!luaG_checkcode(f)) error(S,"bad code"); #endif + S->L->top--; return f; } @@ -209,18 +224,16 @@ static void LoadSignature (LoadState* S) const char* s=LUA_SIGNATURE; while (*s!=0 && ezgetc(S)==*s) ++s; - if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name); + if (*s!=0) error(S,"bad signature"); } static void TestSize (LoadState* S, int s, const char* what) { int r=LoadByte(S); if (r!=s) - luaG_runerror(S->L,"virtual machine mismatch in %s: " - "size of %s is %d but read %d",S->name,what,s,r); + error(S,"bad size of %s (read %d; expected %d)",what,r,s); } -#define TESTSIZE(s,w) TestSize(S,s,w) #define V(v) v/16,v%16 static void LoadHeader (LoadState* S) @@ -230,40 +243,27 @@ static void LoadHeader (LoadState* S) LoadSignature(S); version=LoadByte(S); if (version>VERSION) - luaG_runerror(S->L,"%s too new: " - "read version %d.%d; expected at most %d.%d", - S->name,V(version),V(VERSION)); + error(S,"bad version (read %d.%d; expected at %s %d.%d)", + V(version),"most",V(VERSION)); if (version<VERSION0) /* check last major change */ - luaG_runerror(S->L,"%s too old: " - "read version %d.%d; expected at least %d.%d", - S->name,V(version),V(VERSION0)); + error(S,"bad version (read %d.%d; expected at %s %d.%d)", + V(version),"least",V(VERSION0)); S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ - TESTSIZE(sizeof(int),"int"); - TESTSIZE(sizeof(size_t), "size_t"); - TESTSIZE(sizeof(Instruction), "Instruction"); - TESTSIZE(SIZE_OP, "OP"); - TESTSIZE(SIZE_A, "A"); - TESTSIZE(SIZE_B, "B"); - TESTSIZE(SIZE_C, "C"); - TESTSIZE(sizeof(lua_Number), "number"); + TestSize(S,sizeof(int),"int"); + TestSize(S,sizeof(size_t),"size_t"); + TestSize(S,sizeof(Instruction),"instruction"); + TestSize(S,sizeof(lua_Number),"number"); x=LoadNumber(S); if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */ - luaG_runerror(S->L,"unknown number format in %s",S->name); -} - -static Proto* LoadChunk (LoadState* S) -{ - LoadHeader(S); - return LoadFunction(S,NULL); + error(S,"unknown number format"); } /* ** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* s) { LoadState S; - const char* s=zname(Z); if (*s=='@' || *s=='=') S.name=s+1; else if (*s==LUA_SIGNATURE[0]) @@ -273,7 +273,8 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) S.L=L; S.Z=Z; S.b=buff; - return LoadChunk(&S); + LoadHeader(&S); + return LoadFunction(&S,NULL); } /* diff --git a/src/lundump.h b/src/lundump.h index c7e6959b..26c792a8 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.30 2003/04/07 20:34:20 lhf Exp $ +** $Id: lundump.h,v 1.32 2003/12/09 19:22:19 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -11,21 +11,20 @@ #include "lzio.h" /* load one chunk; from lundump.c */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff); +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char *name); /* find byte order; from lundump.c */ int luaU_endianness (void); /* dump one chunk; from ldump.c */ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data); +int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip); /* print one chunk; from print.c */ void luaU_print (const Proto* Main); /* definitions for headers of binary files */ -#define LUA_SIGNATURE "\033Lua" /* binary files start with "<esc>Lua" */ -#define VERSION 0x50 /* last format change was in 5.0 */ -#define VERSION0 0x50 /* last major change was in 5.0 */ +#define VERSION 0x51 /* last format change was in 5.1 */ +#define VERSION0 0x51 /* last major change was in 5.1 */ /* a multiple of PI for testing native format */ /* multiplying by 1E7 gives non-trivial integer values */ @@ -1,11 +1,10 @@ /* -** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ +** $Id: lvm.c,v 2.2 2004/03/16 12:31:40 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ -#include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -40,7 +39,7 @@ #define MAXTAGLOOP 100 -const TObject *luaV_tonumber (const TObject *obj, TObject *n) { +const TValue *luaV_tonumber (const TValue *obj, TValue *n) { lua_Number num; if (ttisnumber(obj)) return obj; if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { @@ -58,15 +57,18 @@ int luaV_tostring (lua_State *L, StkId obj) { else { char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ lua_number2str(s, nvalue(obj)); - setsvalue2s(obj, luaS_new(L, s)); + setsvalue2s(L, obj, luaS_new(L, s)); return 1; } } -static void traceexec (lua_State *L) { +static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; - if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ + CallInfo *ci = L->ci; + const Instruction *oldpc = ci->u.l.savedpc; + ci->u.l.savedpc = pc; + if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); @@ -74,108 +76,82 @@ static void traceexec (lua_State *L) { } } if (mask & LUA_MASKLINE) { - CallInfo *ci = L->ci; Proto *p = ci_func(ci)->l.p; - int newline = getline(p, pcRel(*ci->u.l.pc, p)); - if (!L->hookinit) { - luaG_inithooks(L); - return; - } - lua_assert(ci->state & CI_HASFRAME); - if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ - ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */ - /* calls linehook when enters a new line or jumps back (loop) */ - if (*ci->u.l.pc <= ci->u.l.savedpc || - newline != getline(p, pcRel(ci->u.l.savedpc, p))) { + int npc = pcRel(pc, p); + int newline = getline(p, npc); + /* call linehook when enter a new function, when jump back (loop), + or when enter a new line */ + if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); - ci = L->ci; /* previous call may reallocate `ci' */ - } - ci->u.l.savedpc = *ci->u.l.pc; } } -static void callTMres (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */ +static void prepTMcall (lua_State *L, const TValue *f, + const TValue *p1, const TValue *p2) { + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ +} + + +static void callTMres (lua_State *L, StkId res) { + ptrdiff_t result = savestack(L, res); + luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1); - L->top--; /* result will be in L->top */ + res = restorestack(L, result); + L->top--; + setobjs2s(L, res, L->top); } -static void callTM (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2, const TObject *p3) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - setobj2s(L->top+3, p3); /* 3th argument */ - luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */ +static void callTM (lua_State *L) { + luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0); } -static const TObject *luaV_index (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); - if (tm == NULL) return &luaO_nilobject; /* no TM */ - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - -static const TObject *luaV_getnotable (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - - -/* -** Function to index a table. -** Receives the table at `t' and the key at `key'. -** leaves the result at `res'. -*/ -const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, - int loop) { - if (loop > MAXTAGLOOP) - luaG_runerror(L, "loop in gettable"); - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TObject *v = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(v)) return v; - else return luaV_index(L, t, key, loop+1); +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + const TValue *res = luaH_get(h, key); /* do a primitive set */ + if (!ttisnil(res) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ + setobj2s(L, val, res); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + prepTMcall(L, tm, t, key); + callTMres(L, val); + return; + } + t = tm; /* else repeat with `tm' */ } - else return luaV_getnotable(L, t, key, loop+1); + luaG_runerror(L, "loop in gettable"); } -/* -** Receives table at `t', key at `key' and value at `val'. -*/ -void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { - const TObject *tm; - int loop = 0; - do { +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); - TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ + TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(oldval, val); /* write barrier */ + setobj2t(L, oldval, val); + luaC_barrier(L, h, val); return; } /* else will try the tag method */ @@ -183,33 +159,33 @@ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { - callTM(L, tm, t, key, val); + prepTMcall(L, tm, t, key); + setobj2s(L, L->top+3, val); /* 3th argument */ + callTM(L); return; } t = tm; /* else repeat with `tm' */ - } while (++loop <= MAXTAGLOOP); + } luaG_runerror(L, "loop in settable"); } -static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { - ptrdiff_t result = savestack(L, res); - const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (!ttisfunction(tm)) return 0; - callTMres(L, tm, p1, p2); - res = restorestack(L, result); /* previous call may change stack */ - setobjs2s(res, L->top); + prepTMcall(L, tm, p1, p2); + callTMres(L, res); return 1; } -static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, +static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { - const TObject *tm1 = fasttm(L, mt1, event); - const TObject *tm2; + const TValue *tm1 = fasttm(L, mt1, event); + const TValue *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); @@ -220,15 +196,16 @@ static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, } -static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2, +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - const TObject *tm1 = luaT_gettmbyobj(L, p1, event); - const TObject *tm2; + 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; - callTMres(L, tm1, p1, p2); + prepTMcall(L, tm1, p1, p2); + callTMres(L, L->top); return !l_isfalse(L->top); } @@ -255,28 +232,28 @@ static int luaV_strcmp (const TString *ls, const TString *rs) { } -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { +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)) return nvalue(l) < nvalue(r); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; + return luaV_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r); } -static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { +static 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)) return nvalue(l) <= nvalue(r); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; + return luaV_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ @@ -285,8 +262,8 @@ static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { } -int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { - const TObject *tm; +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; @@ -295,7 +272,7 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable, + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } @@ -307,7 +284,8 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ - callTMres(L, tm, t1, t2); /* call TM */ + prepTMcall(L, tm, t1, t2); + callTMres(L, L->top); /* call TM */ return !l_isfalse(L->top); } @@ -319,25 +297,25 @@ void luaV_concat (lua_State *L, int total, int last) { if (!tostring(L, top-2) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ + } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ - lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + - cast(lu_mem, tsvalue(top-2)->tsv.len); + lu_mem tl = cast(lu_mem, tsvalue(top-1)->len) + + cast(lu_mem, tsvalue(top-2)->len); char *buffer; int i; while (n < total && tostring(L, top-n-1)) { /* collect total length */ - tl += tsvalue(top-n-1)->tsv.len; + tl += tsvalue(top-n-1)->len; n++; } if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ - size_t l = tsvalue(top-i)->tsv.len; + size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } - setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; @@ -345,10 +323,11 @@ void luaV_concat (lua_State *L, int total, int last) { } -static void Arith (lua_State *L, StkId ra, - const TObject *rb, const TObject *rc, TMS op) { - TObject tempb, tempc; - const TObject *b, *c; +static StkId Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op, const Instruction *pc) { + TValue tempb, tempc; + const TValue *b, *c; + L->ci->u.l.savedpc = pc; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { switch (op) { @@ -357,13 +336,11 @@ static void Arith (lua_State *L, StkId ra, case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; case TM_POW: { - const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); - ptrdiff_t res = savestack(L, ra); + const TValue *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); if (!ttisfunction(f)) luaG_runerror(L, "`__pow' (`^' operator) is not a function"); - callTMres(L, f, b, c); - ra = restorestack(L, res); /* previous call may change stack */ - setobjs2s(ra, L->top); + prepTMcall(L, f, b, c); + callTMres(L, ra); break; } default: lua_assert(0); break; @@ -371,6 +348,7 @@ static void Arith (lua_State *L, StkId ra, } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); + return L->base; } @@ -383,63 +361,58 @@ static void Arith (lua_State *L, StkId ra, #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ -#define XRA(i) (L->base+GETARG_A(i)) -#define RB(i) (base+GETARG_B(i)) -#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK) -#define RC(i) (base+GETARG_C(i)) -#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK) -#define KBx(i) (k+GETARG_Bx(i)) +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + (GETARG_B(i) < MAXSTACK) ? base+GETARG_B(i) : k+GETARG_B(i)-MAXSTACK) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + (GETARG_C(i) < MAXSTACK) ? base+GETARG_C(i) : k+GETARG_C(i)-MAXSTACK) +#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) #define dojump(pc, i) ((pc) += (i)) -StkId luaV_execute (lua_State *L) { +StkId luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; - TObject *k; + TValue *k; + StkId base; const Instruction *pc; callentry: /* entry point when calling new functions */ - if (L->hookmask & LUA_MASKCALL) { - L->ci->u.l.pc = &pc; + if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); - } retentry: /* entry point when returning to old functions */ - L->ci->u.l.pc = &pc; - lua_assert(L->ci->state == CI_SAVEDPC || - L->ci->state == (CI_SAVEDPC | CI_CALLING)); - L->ci->state = CI_HASFRAME; /* activate frame */ pc = L->ci->u.l.savedpc; - cl = &clvalue(L->base - 1)->l; + base = L->base; + cl = &clvalue(base - 1)->l; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; - StkId base, ra; + StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->ci->state & CI_YIELD) { /* did hook yield? */ + traceexec(L, pc); /***/ + if (L->isSuspended) { /* did hook yield? */ L->ci->u.l.savedpc = pc - 1; - L->ci->state = CI_YIELD | CI_SAVEDPC; return NULL; } + base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ - base = L->base; ra = RA(i); - lua_assert(L->ci->state & CI_HASFRAME); - lua_assert(base == L->ci->base); + lua_assert(base == L->ci->base && base == L->base); lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); switch (GET_OPCODE(i)) { case OP_MOVE: { - setobjs2s(ra, RB(i)); + setobjs2s(L, ra, RB(i)); break; } case OP_LOADK: { - setobj2s(ra, KBx(i)); + setobj2s(L, ra, KBx(i)); break; } case OP_LOADBOOL: { @@ -448,7 +421,7 @@ StkId luaV_execute (lua_State *L) { break; } case OP_LOADNIL: { - TObject *rb = RB(i); + TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); @@ -456,122 +429,115 @@ StkId luaV_execute (lua_State *L) { } case OP_GETUPVAL: { int b = GETARG_B(i); - setobj2s(ra, cl->upvals[b]->v); + setobj2s(L, ra, cl->upvals[b]->v); break; } case OP_GETGLOBAL: { - TObject *rb = KBx(i); - const TObject *v; + TValue *rb = KBx(i); lua_assert(ttisstring(rb) && ttistable(&cl->g)); - v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); + L->ci->u.l.savedpc = pc; + luaV_gettable(L, &cl->g, rb, ra); /***/ + base = L->base; break; } case OP_GETTABLE: { - StkId rb = RB(i); - TObject *rc = RKC(i); - if (ttistable(rb)) { - const TObject *v = luaH_get(hvalue(rb), rc); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); + L->ci->u.l.savedpc = pc; + luaV_gettable(L, RB(i), RKC(i), ra); /***/ + base = L->base; break; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - luaV_settable(L, &cl->g, KBx(i), ra); + L->ci->u.l.savedpc = pc; + luaV_settable(L, &cl->g, KBx(i), ra); /***/ + base = L->base; break; } case OP_SETUPVAL: { - int b = GETARG_B(i); - setobj(cl->upvals[b]->v, ra); /* write barrier */ + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_barrier(L, uv, ra); break; } case OP_SETTABLE: { - luaV_settable(L, ra, RKB(i), RKC(i)); + L->ci->u.l.savedpc = pc; + luaV_settable(L, ra, RKB(i), RKC(i)); /***/ + base = L->base; break; } case OP_NEWTABLE: { int b = GETARG_B(i); b = fb2int(b); - sethvalue(ra, luaH_new(L, b, GETARG_C(i))); - luaC_checkGC(L); + sethvalue(L, ra, luaH_new(L, b, GETARG_C(i))); + L->ci->u.l.savedpc = pc; + luaC_checkGC(L); /***/ + base = L->base; break; } case OP_SELF: { StkId rb = RB(i); - TObject *rc = RKC(i); - runtime_check(L, ttisstring(rc)); - setobjs2s(ra+1, rb); - if (ttistable(rb)) { - const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); + setobjs2s(L, ra+1, rb); + L->ci->u.l.savedpc = pc; + luaV_gettable(L, rb, RKC(i), ra); /***/ + base = L->base; break; } case OP_ADD: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) + nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_ADD); + base = Arith(L, ra, rb, rc, TM_ADD, pc); /***/ break; } case OP_SUB: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) - nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_SUB); + base = Arith(L, ra, rb, rc, TM_SUB, pc); /***/ break; } case OP_MUL: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) * nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_MUL); + base = Arith(L, ra, rb, rc, TM_MUL, pc); /***/ break; } case OP_DIV: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) / nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_DIV); + base = Arith(L, ra, rb, rc, TM_DIV, pc); /***/ break; } case OP_POW: { - Arith(L, ra, RKB(i), RKC(i), TM_POW); + base = Arith(L, ra, RKB(i), RKC(i), TM_POW, pc); /***/ break; } case OP_UNM: { - const TObject *rb = RB(i); - TObject temp; + const TValue *rb = RB(i); + TValue temp; if (tonumber(rb, &temp)) { setnvalue(ra, -nvalue(rb)); } else { setnilvalue(&temp); - if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) + L->ci->u.l.savedpc = pc; + if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) /***/ luaG_aritherror(L, RB(i), &temp); + base = L->base; } break; } @@ -583,10 +549,11 @@ StkId luaV_execute (lua_State *L) { case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ + L->ci->u.l.savedpc = pc; + luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ /***/ + luaC_checkGC(L); /***/ base = L->base; - setobjs2s(RA(i), base+b); - luaC_checkGC(L); + setobjs2s(L, RA(i), base+b); break; } case OP_JMP: { @@ -594,42 +561,46 @@ StkId luaV_execute (lua_State *L) { break; } case OP_EQ: { - if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; + L->ci->u.l.savedpc = pc; + if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(pc, GETARG_sBx(*pc) + 1); + base = L->base; break; } case OP_LT: { - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; + L->ci->u.l.savedpc = pc; + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(pc, GETARG_sBx(*pc) + 1); + base = L->base; break; } case OP_LE: { - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; + L->ci->u.l.savedpc = pc; + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(pc, GETARG_sBx(*pc) + 1); + base = L->base; break; } case OP_TEST: { - TObject *rb = RB(i); + TValue *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { - setobjs2s(ra, rb); + setobjs2s(L, ra, rb); dojump(pc, GETARG_sBx(*pc) + 1); } break; } case OP_CALL: - case OP_TAILCALL: { + case OP_TAILCALL: { /***/ StkId firstResult; int b = GETARG_B(i); - int nresults; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - nresults = GETARG_C(i) - 1; + L->ci->u.l.savedpc = pc; firstResult = luaD_precall(L, ra); if (firstResult) { + int nresults = GETARG_C(i) - 1; if (firstResult > L->top) { /* yield? */ - lua_assert(L->ci->state == (CI_C | CI_YIELD)); (L->ci - 1)->u.l.savedpc = pc; - (L->ci - 1)->state = CI_SAVEDPC; return NULL; } /* it was a C function (`precall' called it); adjust results */ @@ -637,45 +608,37 @@ StkId luaV_execute (lua_State *L) { if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ - (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ - (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); - } + if (GET_OPCODE(i) == OP_CALL) /* regular call? */ + nexeccalls++; else { /* tail call: put new frame in place of previous one */ int aux; base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ ra = RA(i); if (L->openupval) luaF_close(L, base); for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ - setobjs2s(base+aux-1, ra+aux); + setobjs2s(L, base+aux-1, ra+aux); (L->ci - 1)->top = L->top = base+aux; /* correct top */ - lua_assert(L->ci->state & CI_SAVEDPC); (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ - (L->ci - 1)->state = CI_SAVEDPC; L->ci--; /* remove new frame */ L->base = L->ci->base; } goto callentry; } + base = L->base; break; } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; - lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); - L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->u.l.savedpc = pc; - /* previous function was running `here'? */ - if (!(ci->state & CI_CALLING)) { - lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); + if (--nexeccalls == 0) /* was previous function running `here'? */ return ra; /* no: return */ - } else { /* yes: continue its execution */ int nresults; - lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); + lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); @@ -684,49 +647,54 @@ StkId luaV_execute (lua_State *L) { } } case OP_FORLOOP: { - lua_Number step, idx, limit; - const TObject *plimit = ra+1; - const TObject *pstep = ra+2; - if (!ttisnumber(ra)) - luaG_runerror(L, "`for' initial value must be a number"); - if (!tonumber(plimit, ra+1)) - luaG_runerror(L, "`for' limit must be a number"); - if (!tonumber(pstep, ra+2)) - luaG_runerror(L, "`for' step must be a number"); - step = nvalue(pstep); - idx = nvalue(ra) + step; /* increment index */ - limit = nvalue(plimit); + lua_Number step = nvalue(ra+2); + lua_Number idx = nvalue(ra) + step; /* increment index */ + lua_Number limit = nvalue(ra+1); if (step > 0 ? idx <= limit : idx >= limit) { dojump(pc, GETARG_sBx(i)); /* jump back */ - chgnvalue(ra, idx); /* update index */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ } break; } + case OP_FORPREP: { /***/ + const TValue *init = ra; + const TValue *plimit = ra+1; + const TValue *pstep = ra+2; + L->ci->u.l.savedpc = pc; + if (!tonumber(init, ra)) + luaG_runerror(L, "`for' initial value must be a number"); + else if (!tonumber(plimit, ra+1)) + luaG_runerror(L, "`for' limit must be a number"); + else if (!tonumber(pstep, ra+2)) + luaG_runerror(L, "`for' step must be a number"); + setnvalue(ra, nvalue(ra) - nvalue(pstep)); + dojump(pc, GETARG_sBx(i)); + break; + } case OP_TFORLOOP: { - int nvar = GETARG_C(i) + 1; - StkId cb = ra + nvar + 2; /* call base */ - setobjs2s(cb, ra); - setobjs2s(cb+1, ra+1); - setobjs2s(cb+2, ra+2); + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ - luaD_call(L, cb, nvar); + L->ci->u.l.savedpc = pc; + luaD_call(L, cb, GETARG_C(i)); /***/ L->top = L->ci->top; - ra = XRA(i) + 2; /* final position of first result */ - cb = ra + nvar; - do { /* move results to proper positions */ - nvar--; - setobjs2s(ra+nvar, cb+nvar); - } while (nvar > 0); - if (ttisnil(ra)) /* break loop? */ + base = L->base; + cb = RA(i) + 3; /* previous call may change the stack */ + if (ttisnil(cb)) /* break loop? */ pc++; /* skip jump (break loop) */ - else + else { + setobjs2s(L, cb-1, cb); /* save control variable */ dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ + } break; } case OP_TFORPREP: { /* for compatibility only */ if (ttistable(ra)) { - setobjs2s(ra+1, ra); - setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); + setobjs2s(L, ra+1, ra); + setobj2s(L, ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } dojump(pc, GETARG_sBx(i)); break; @@ -746,8 +714,11 @@ StkId luaV_execute (lua_State *L) { L->top = L->ci->top; } bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ - for (; n > 0; n--) - setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ + for (; n > 0; n--) { + TValue *val = ra+n; + setobj2t(L, luaH_setnum(L, h, bc+n), val); + luaC_barrier(L, h, val); + } break; } case OP_CLOSE: { @@ -770,12 +741,13 @@ StkId luaV_execute (lua_State *L) { ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } - setclvalue(ra, ncl); - luaC_checkGC(L); + setclvalue(L, ra, ncl); + L->ci->u.l.savedpc = pc; + luaC_checkGC(L); /***/ + base = L->base; break; } } } } - @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.47 2002/11/14 16:16:21 roberto Exp $ +** $Id: lvm.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -22,14 +22,13 @@ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); -int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2); -const TObject *luaV_tonumber (const TObject *obj, TObject *n); +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +const TValue *luaV_tonumber (const TValue *obj, TValue *n); int luaV_tostring (lua_State *L, StkId obj); -const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, - int loop); -void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val); -StkId luaV_execute (lua_State *L); +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); +StkId luaV_execute (lua_State *L, int nexeccalls); void luaV_concat (lua_State *L, int total, int last); #endif @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.24 2003/03/20 16:00:56 roberto Exp $ +** $Id: lzio.c,v 1.28 2003/11/18 10:44:53 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -13,12 +13,17 @@ #include "llimits.h" #include "lmem.h" +#include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; - const char *buff = z->reader(NULL, z->data, &size); + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; z->p = buff; @@ -37,10 +42,10 @@ int luaZ_lookahead (ZIO *z) { } -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { +void luaZ_init (lua_State *L, ZIO *z, lua_Chunkreader reader, void *data) { + z->L = L; z->reader = reader; z->data = data; - z->name = name; z->n = 0; z->p = NULL; } @@ -72,8 +77,7 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { if (n > buff->buffsize) { if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char); - buff->buffsize = n; + luaZ_resizebuffer(L, buff, n); } return buff->buffer; } @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.15 2003/03/20 16:00:56 roberto Exp $ +** $Id: lzio.h,v 1.19 2003/10/03 16:05:34 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -10,6 +10,8 @@ #include "lua.h" +#include "lmem.h" + #define EOZ (-1) /* end of stream */ @@ -20,9 +22,7 @@ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) -#define zname(z) ((z)->name) - -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name); +void luaZ_init (lua_State *L, ZIO *z, lua_Chunkreader reader, void *data); size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ int luaZ_lookahead (ZIO *z); @@ -30,6 +30,7 @@ int luaZ_lookahead (ZIO *z); typedef struct Mbuffer { char *buffer; + size_t n; size_t buffsize; } Mbuffer; @@ -38,8 +39,12 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) -#define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + #define luaZ_resizebuffer(L, buff, size) \ (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ @@ -48,6 +53,7 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + /* --------- Private Part ------------------ */ struct Zio { @@ -55,7 +61,7 @@ struct Zio { const char *p; /* current position in buffer */ lua_Chunkreader reader; void* data; /* additional data */ - const char *name; + lua_State *L; /* Lua state (for reader) */ }; |