diff options
| author | Emil Renner Berthing <esmil@mailme.dk> | 2012-07-15 01:06:01 +0200 | 
|---|---|---|
| committer | Emil Renner Berthing <esmil@mailme.dk> | 2012-07-23 17:36:24 +0200 | 
| commit | 78e6e89431e4ef9419a716f246f1f3cfaf7d9dfe (patch) | |
| tree | d9e476dfee06bf8ba6dcf4499fb78ce1350728fe | |
| parent | 3a1c6f4e205c8c6d28abc641e568f2fa6362c654 (diff) | |
| download | lem-78e6e89431e4ef9419a716f246f1f3cfaf7d9dfe.tar.gz lem-78e6e89431e4ef9419a716f246f1f3cfaf7d9dfe.tar.xz lem-78e6e89431e4ef9419a716f246f1f3cfaf7d9dfe.zip | |
Lua 5.2.1
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile.in | 11 | ||||
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | lua.c | 52 | ||||
| -rw-r--r-- | lua/Makefile | 2 | ||||
| -rw-r--r-- | lua/amalg.c | 52 | ||||
| -rw-r--r-- | lua/lapi.c | 20 | ||||
| -rw-r--r-- | lua/lauxlib.c | 19 | ||||
| -rw-r--r-- | lua/lbaselib.c | 3 | ||||
| -rw-r--r-- | lua/lcorolib.c | 5 | ||||
| -rw-r--r-- | lua/ldblib.c | 21 | ||||
| -rw-r--r-- | lua/ldebug.c | 13 | ||||
| -rw-r--r-- | lua/ldo.c | 32 | ||||
| -rw-r--r-- | lua/ldump.c | 7 | ||||
| -rw-r--r-- | lua/lfunc.c | 20 | ||||
| -rw-r--r-- | lua/lfunc.h | 5 | ||||
| -rw-r--r-- | lua/lgc.c | 456 | ||||
| -rw-r--r-- | lua/lgc.h | 10 | ||||
| -rw-r--r-- | lua/llex.c | 27 | ||||
| -rw-r--r-- | lua/llimits.h | 17 | ||||
| -rw-r--r-- | lua/lmathlib.c | 12 | ||||
| -rw-r--r-- | lua/lmem.c | 18 | ||||
| -rw-r--r-- | lua/loadlib.c | 97 | ||||
| -rw-r--r-- | lua/lobject.h | 75 | ||||
| -rw-r--r-- | lua/lopcodes.c | 3 | ||||
| -rw-r--r-- | lua/loslib.c | 17 | ||||
| -rw-r--r-- | lua/lparser.c | 153 | ||||
| -rw-r--r-- | lua/lparser.h | 6 | ||||
| -rw-r--r-- | lua/lstate.c | 42 | ||||
| -rw-r--r-- | lua/lstate.h | 20 | ||||
| -rw-r--r-- | lua/lstring.c | 115 | ||||
| -rw-r--r-- | lua/lstring.h | 17 | ||||
| -rw-r--r-- | lua/lstrlib.c | 35 | ||||
| -rw-r--r-- | lua/ltable.c | 27 | ||||
| -rw-r--r-- | lua/lua.c | 31 | ||||
| -rw-r--r-- | lua/lua.h | 8 | ||||
| -rw-r--r-- | lua/luaconf.h.in (renamed from lua/luaconf.h) | 112 | ||||
| -rw-r--r-- | lua/lundump.c | 38 | ||||
| -rw-r--r-- | lua/lundump.h | 4 | ||||
| -rw-r--r-- | lua/lvm.c | 50 | ||||
| -rw-r--r-- | lua/lzio.c | 4 | 
41 files changed, 992 insertions, 667 deletions
| @@ -4,6 +4,7 @@  config.status  config.log  Makefile +lua/luaconf.h  libev/ev-config.h  lem.pc  lem diff --git a/Makefile.in b/Makefile.in index bf4d53d..e374abe 100644 --- a/Makefile.in +++ b/Makefile.in @@ -43,7 +43,7 @@ endif  all: $(programs) lem.pc  libev.o: CFLAGS += -w -lua/amalg.o: CFLAGS += -DLUA_USE_LINUX -DLUA_ROOT='"$(prefix)/"' +lua.o: lua/luaconf.h  %.o: %.c  	$E '  CC    $@' @@ -57,6 +57,13 @@ lem: $(objects)  	$E '  CCLD  $@'  	$Q$(CC) $(CFLAGS) -fPIC -nostartfiles $(SHARED) $^ -o $@ $(LDFLAGS) +lua/luaconf.h: lua/luaconf.h.in +	$E '  SED > $@' +	$Q$(SED) \ +	  -e 's|@path@|$(lua_path)|' \ +	  -e 's|@cpath@|$(lua_cpath)|' \ +	  $< > $@ +  %.pc: %.pc.in  	$E '  SED > $@'  	$Q$(SED) \ @@ -102,4 +109,4 @@ lem-repl-install: lem-repl | $(bindir)  install: lem.pc-install $(headers:%=%-install) $(programs:%=%-install) $(scripts:%=%-install)  clean: -	rm -f $(programs) lem.pc *.o lua/*.o +	rm -f lem lua/luaconf.h lem.pc *.o *.so diff --git a/configure.ac b/configure.ac index c07b2fc..a62d657 100644 --- a/configure.ac +++ b/configure.ac @@ -90,7 +90,7 @@ AS_CASE(["x$with_lua"],  AS_IF([test "x$with_lua" = 'xbuiltin'],    [AC_CHECK_LIB([m], [sin])]    [AC_SEARCH_LIBS([dlopen], [dl])] -  [objects="lua/amalg.o $objects"] +  [objects="lua.o $objects"]    [headers="lua/luaconf.h lua/lua.h lua/lauxlib.h $headers"]    [CPPFLAGS="$CPPFLAGS -Ilua"]    [AS_IF([test "x$lmoddir" = 'x'], [lmoddir="\${datarootdir}/lua/$builtin_lua_version"])] @@ -0,0 +1,52 @@ +/* setup for luaconf.h */ +#define LUA_CORE +#define LUA_LIB +#define ltable_c +#define lvm_c +#include "luaconf.h" + +/* do not export internal symbols */ +#undef LUAI_FUNC +#undef LUAI_DDEC +#undef LUAI_DDEF +#define LUAI_FUNC	static +#define LUAI_DDEC	static +#define LUAI_DDEF	static + +/* core */ +#include "lua/lapi.c" +#include "lua/lcode.c" +#include "lua/lctype.c" +#include "lua/ldebug.c" +#include "lua/ldo.c" +#include "lua/ldump.c" +#include "lua/lfunc.c" +#include "lua/lgc.c" +#include "lua/llex.c" +#include "lua/lmem.c" +#include "lua/lobject.c" +#include "lua/lopcodes.c" +#include "lua/lparser.c" +#include "lua/lstate.c" +#include "lua/lstring.c" +#include "lua/ltable.c" +#include "lua/ltm.c" +#include "lua/lundump.c" +#include "lua/lvm.c" +#include "lua/lzio.c" + +/* auxiliary library */ +#include "lua/lauxlib.c" + +/* standard library */ +#include "lua/lbaselib.c" +#include "lua/lbitlib.c" +#include "lua/lcorolib.c" +#include "lua/ldblib.c" +#include "lua/liolib.c" +#include "lua/lmathlib.c" +#include "lua/loadlib.c" +#include "lua/loslib.c" +#include "lua/lstrlib.c" +#include "lua/ltablib.c" +#include "lua/linit.c" diff --git a/lua/Makefile b/lua/Makefile index bba1693..8c9ee67 100644 --- a/lua/Makefile +++ b/lua/Makefile @@ -56,7 +56,7 @@ o:	$(ALL_O)  a:	$(ALL_A)  $(LUA_A): $(BASE_O) -	$(AR) $@ $? +	$(AR) $@ $(BASE_O)  	$(RANLIB) $@  $(LUA_T): $(LUA_O) $(LUA_A) diff --git a/lua/amalg.c b/lua/amalg.c deleted file mode 100644 index a24267f..0000000 --- a/lua/amalg.c +++ /dev/null @@ -1,52 +0,0 @@ -/* setup for luaconf.h */ -#define LUA_CORE -#define LUA_LIB -#define ltable_c -#define lvm_c -#include "luaconf.h" - -/* do not export internal symbols */ -#undef LUAI_FUNC -#undef LUAI_DDEC -#undef LUAI_DDEF -#define LUAI_FUNC	static -#define LUAI_DDEC	static -#define LUAI_DDEF	static - -/* core -- used by all */ -#include "lapi.c" -#include "lcode.c" -#include "lctype.c" -#include "ldebug.c" -#include "ldo.c" -#include "ldump.c" -#include "lfunc.c" -#include "lgc.c" -#include "llex.c" -#include "lmem.c" -#include "lobject.c" -#include "lopcodes.c" -#include "lparser.c" -#include "lstate.c" -#include "lstring.c" -#include "ltable.c" -#include "ltm.c" -#include "lundump.c" -#include "lvm.c" -#include "lzio.c" - -/* auxiliary library -- used by all */ -#include "lauxlib.c" - -/* standard library  -- not used by luac */ -#include "lbaselib.c" -#include "lbitlib.c" -#include "lcorolib.c" -#include "ldblib.c" -#include "liolib.c" -#include "lmathlib.c" -#include "loadlib.c" -#include "loslib.c" -#include "lstrlib.c" -#include "ltablib.c" -#include "linit.c" @@ -1,5 +1,5 @@  /* -** $Id: lapi.c,v 2.159 2011/11/30 12:32:05 roberto Exp $ +** $Id: lapi.c,v 2.164 2012/06/08 15:14:04 roberto Exp $  ** Lua API  ** See Copyright Notice in lua.h  */ @@ -950,7 +950,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,      ci->u.c.k = k;  /* save continuation */      ci->u.c.ctx = ctx;  /* save context */      /* save information for error recovery */ -    ci->u.c.extra = savestack(L, c.func); +    ci->extra = savestack(L, c.func);      ci->u.c.old_allowhook = L->allowhook;      ci->u.c.old_errfunc = L->errfunc;      L->errfunc = func; @@ -1045,17 +1045,17 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {      }      case LUA_GCSTEP: {        if (g->gckind == KGC_GEN) {  /* generational mode? */ -        res = (g->lastmajormem == 0);  /* 1 if will do major collection */ +        res = (g->GCestimate == 0);  /* true if it will do major collection */          luaC_forcestep(L);  /* do a single step */        }        else { -        while (data-- >= 0) { -          luaC_forcestep(L); -          if (g->gcstate == GCSpause) {  /* end of cycle? */ -            res = 1;  /* signal it */ -            break; -          } -        } +       lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE; +       if (g->gcrunning) +         debt += g->GCdebt;  /* include current debt */ +       luaE_setdebt(g, debt); +       luaC_forcestep(L); +       if (g->gcstate == GCSpause)  /* end of cycle? */ +         res = 1;  /* signal it */        }        break;      } diff --git a/lua/lauxlib.c b/lua/lauxlib.c index 0aa80fd..36ae7e6 100644 --- a/lua/lauxlib.c +++ b/lua/lauxlib.c @@ -1,5 +1,5 @@  /* -** $Id: lauxlib.c,v 1.240 2011/12/06 16:33:55 roberto Exp $ +** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 roberto Exp $  ** Auxiliary functions for building Lua libraries  ** See Copyright Notice in lua.h  */ @@ -520,11 +520,11 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {  LUALIB_API int luaL_ref (lua_State *L, int t) {    int ref; -  t = lua_absindex(L, t);    if (lua_isnil(L, -1)) {      lua_pop(L, 1);  /* remove from stack */      return LUA_REFNIL;  /* `nil' has a unique fixed reference */    } +  t = lua_absindex(L, t);    lua_rawgeti(L, t, freelist);  /* get first free element */    ref = (int)lua_tointeger(L, -1);  /* ref = t[freelist] */    lua_pop(L, 1);  /* remove it from stack */ @@ -616,8 +616,10 @@ static int skipBOM (LoadF *lf) {  static int skipcomment (LoadF *lf, int *cp) {    int c = *cp = skipBOM(lf);    if (c == '#') {  /* first line is a comment (Unix exec. file)? */ -    while ((c = getc(lf->f)) != EOF && c != '\n') ;  /* skip first line */ -    *cp = getc(lf->f);  /* skip end-of-line */ +    do {  /* skip first line */ +      c = getc(lf->f); +    } while (c != EOF && c != '\n') ; +    *cp = getc(lf->f);  /* skip end-of-line, if present */      return 1;  /* there was a comment */    }    else return 0;  /* no comment */ @@ -843,6 +845,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname,  ** Returns with only the table at the stack.  */  LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { +  luaL_checkversion(L);    luaL_checkstack(L, nup, "too many upvalues");    for (; l->name != NULL; l++) {  /* fill the table with given functions */      int i; @@ -863,8 +866,8 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {    lua_getfield(L, idx, fname);    if (lua_istable(L, -1)) return 1;  /* table already there */    else { -    idx = lua_absindex(L, idx);      lua_pop(L, 1);  /* remove previous result */ +    idx = lua_absindex(L, idx);      lua_newtable(L);      lua_pushvalue(L, -1);  /* copy to be left at top */      lua_setfield(L, idx, fname);  /* assign new table to field */ @@ -889,10 +892,8 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname,    lua_setfield(L, -2, modname);  /* _LOADED[modname] = module */    lua_pop(L, 1);  /* remove _LOADED table */    if (glb) { -    lua_pushglobaltable(L); -    lua_pushvalue(L, -2);  /* copy of 'mod' */ -    lua_setfield(L, -2, modname);  /* _G[modname] = module */ -    lua_pop(L, 1);  /* remove _G table */ +    lua_pushvalue(L, -1);  /* copy of 'mod' */ +    lua_setglobal(L, modname);  /* _G[modname] = module */    }  } diff --git a/lua/lbaselib.c b/lua/lbaselib.c index 1dfae30..dbfcb02 100644 --- a/lua/lbaselib.c +++ b/lua/lbaselib.c @@ -1,5 +1,5 @@  /* -** $Id: lbaselib.c,v 1.273 2011/11/30 13:03:24 roberto Exp $ +** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $  ** Basic library  ** See Copyright Notice in lua.h  */ @@ -293,6 +293,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {    lua_pushvalue(L, 1);  /* get function */    lua_call(L, 0, 1);  /* call it */    if (lua_isnil(L, -1)) { +    lua_pop(L, 1);  /* pop result */      *size = 0;      return NULL;    } diff --git a/lua/lcorolib.c b/lua/lcorolib.c index 0edde26..c7932d9 100644 --- a/lua/lcorolib.c +++ b/lua/lcorolib.c @@ -1,5 +1,5 @@  /* -** $Id: lcorolib.c,v 1.3 2011/08/23 17:24:34 roberto Exp $ +** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $  ** Coroutine Library  ** See Copyright Notice in lua.h  */ @@ -80,8 +80,9 @@ static int luaB_auxwrap (lua_State *L) {  static int luaB_cocreate (lua_State *L) { -  lua_State *NL = lua_newthread(L); +  lua_State *NL;    luaL_checktype(L, 1, LUA_TFUNCTION); +  NL = lua_newthread(L);    lua_pushvalue(L, 1);  /* move function to top */    lua_xmove(L, NL, 1);  /* move function from L to NL */    return 1; diff --git a/lua/ldblib.c b/lua/ldblib.c index 3c2f159..c022694 100644 --- a/lua/ldblib.c +++ b/lua/ldblib.c @@ -1,5 +1,5 @@  /* -** $Id: ldblib.c,v 1.131 2011/10/24 14:54:05 roberto Exp $ +** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $  ** Interface from Lua to its debug API  ** See Copyright Notice in lua.h  */ @@ -253,14 +253,15 @@ static int db_upvaluejoin (lua_State *L) {  } -#define gethooktable(L)	luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); +#define gethooktable(L)	luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)  static void hookf (lua_State *L, lua_Debug *ar) {    static const char *const hooknames[] =      {"call", "return", "line", "count", "tail call"};    gethooktable(L); -  lua_rawgetp(L, -1, L); +  lua_pushthread(L); +  lua_rawget(L, -2);    if (lua_isfunction(L, -1)) {      lua_pushstring(L, hooknames[(int)ar->event]);      if (ar->currentline >= 0) @@ -306,10 +307,15 @@ static int db_sethook (lua_State *L) {      count = luaL_optint(L, arg+3, 0);      func = hookf; mask = makemask(smask, count);    } -  gethooktable(L); +  if (gethooktable(L) == 0) {  /* creating hook table? */ +    lua_pushstring(L, "k"); +    lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */ +    lua_pushvalue(L, -1); +    lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */ +  } +  lua_pushthread(L1); lua_xmove(L1, L, 1);    lua_pushvalue(L, arg+1); -  lua_rawsetp(L, -2, L1);  /* set new hook */ -  lua_pop(L, 1);  /* remove hook table */ +  lua_rawset(L, -3);  /* set new hook */    lua_sethook(L1, func, mask, count);  /* set hooks */    return 0;  } @@ -325,7 +331,8 @@ static int db_gethook (lua_State *L) {      lua_pushliteral(L, "external hook");    else {      gethooktable(L); -    lua_rawgetp(L, -1, L1);   /* get hook */ +    lua_pushthread(L1); lua_xmove(L1, L, 1); +    lua_rawget(L, -2);   /* get hook */      lua_remove(L, -2);  /* remove hook table */    }    lua_pushstring(L, unmakemask(mask, buff)); diff --git a/lua/ldebug.c b/lua/ldebug.c index 31b7ae4..43f8f04 100644 --- a/lua/ldebug.c +++ b/lua/ldebug.c @@ -1,5 +1,5 @@  /* -** $Id: ldebug.c,v 2.88 2011/11/30 12:43:51 roberto Exp $ +** $Id: ldebug.c,v 2.89 2012/01/20 22:05:50 roberto Exp $  ** Debug Interface  ** See Copyright Notice in lua.h  */ @@ -30,6 +30,9 @@ +#define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_TCCL) + +  static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); @@ -173,7 +176,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {  static void funcinfo (lua_Debug *ar, Closure *cl) { -  if (cl == NULL || cl->c.isC) { +  if (noLuaClosure(cl)) {      ar->source = "=[C]";      ar->linedefined = -1;      ar->lastlinedefined = -1; @@ -191,7 +194,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {  static void collectvalidlines (lua_State *L, Closure *f) { -  if (f == NULL || f->c.isC) { +  if (noLuaClosure(f)) {      setnilvalue(L->top);      incr_top(L);    } @@ -210,7 +213,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {  static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, -                    Closure *f, CallInfo *ci) { +                       Closure *f, CallInfo *ci) {    int status = 1;    for (; *what; what++) {      switch (*what) { @@ -224,7 +227,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,        }        case 'u': {          ar->nups = (f == NULL) ? 0 : f->c.nupvalues; -        if (f == NULL || f->c.isC) { +        if (noLuaClosure(f)) {            ar->isvararg = 1;            ar->nparams = 0;          } @@ -1,5 +1,5 @@  /* -** $Id: ldo.c,v 2.102 2011/11/29 15:55:08 roberto Exp $ +** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 roberto Exp $  ** Stack and Call structure of Lua  ** See Copyright Notice in lua.h  */ @@ -402,8 +402,6 @@ static void finishCcall (lua_State *L) {    int n;    lua_assert(ci->u.c.k != NULL);  /* must have a continuation */    lua_assert(L->nny == 0); -  /* finish 'luaD_call' */ -  L->nCcalls--;    /* finish 'lua_callk' */    adjustresults(L, ci->nresults);    /* call continuation function */ @@ -453,7 +451,7 @@ static int recover (lua_State *L, int status) {    CallInfo *ci = findpcall(L);    if (ci == NULL) return 0;  /* no recovery point */    /* "finish" luaD_pcall */ -  oldtop = restorestack(L, ci->u.c.extra); +  oldtop = restorestack(L, ci->extra);    luaF_close(L, oldtop);    seterrorobj(L, status, oldtop);    L->ci = ci; @@ -484,9 +482,10 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {  ** do the work for 'lua_resume' in protected mode  */  static void resume (lua_State *L, void *ud) { +  int nCcalls = L->nCcalls;    StkId firstArg = cast(StkId, ud);    CallInfo *ci = L->ci; -  if (L->nCcalls >= LUAI_MAXCCALLS) +  if (nCcalls >= LUAI_MAXCCALLS)      resume_error(L, "C stack overflow", firstArg);    if (L->status == LUA_OK) {  /* may be starting a coroutine */      if (ci != &L->base_ci)  /* not in base level? */ @@ -499,10 +498,10 @@ static void resume (lua_State *L, void *ud) {      resume_error(L, "cannot resume dead coroutine", firstArg);    else {  /* resuming from previous yield */      L->status = LUA_OK; +    ci->func = restorestack(L, ci->extra);      if (isLua(ci))  /* yielded inside a hook? */        luaV_execute(L);  /* just continue running Lua code */      else {  /* 'common' yield */ -      ci->func = restorestack(L, ci->u.c.extra);        if (ci->u.c.k != NULL) {  /* does it have a continuation? */          int n;          ci->u.c.status = LUA_YIELD;  /* 'default' status */ @@ -513,11 +512,11 @@ static void resume (lua_State *L, void *ud) {          api_checknelems(L, n);          firstArg = L->top - n;  /* yield results come from continuation */        } -      L->nCcalls--;  /* finish 'luaD_call' */        luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */      }      unroll(L, NULL);    } +  lua_assert(nCcalls == L->nCcalls);  } @@ -564,13 +563,13 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {        luaG_runerror(L, "attempt to yield from outside a coroutine");    }    L->status = LUA_YIELD; +  ci->extra = savestack(L, ci->func);  /* save current 'func' */    if (isLua(ci)) {  /* inside a hook? */      api_check(L, k == NULL, "hooks cannot continue after yielding");    }    else {      if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */        ci->u.c.ctx = ctx;  /* save context */ -    ci->u.c.extra = savestack(L, ci->func);  /* save current 'func' */      ci->func = L->top - nresults - 1;  /* protect stack below results */      luaD_throw(L, LUA_YIELD);    } @@ -627,24 +626,23 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {  static void f_parser (lua_State *L, void *ud) {    int i; -  Proto *tf;    Closure *cl;    struct SParser *p = cast(struct SParser *, ud);    int c = zgetc(p->z);  /* read first character */    if (c == LUA_SIGNATURE[0]) {      checkmode(L, p->mode, "binary"); -    tf = luaU_undump(L, p->z, &p->buff, p->name); +    cl = luaU_undump(L, p->z, &p->buff, p->name);    }    else {      checkmode(L, p->mode, "text"); -    tf = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); +    cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); +  } +  lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); +  for (i = 0; i < cl->l.nupvalues; i++) {  /* initialize upvalues */ +    UpVal *up = luaF_newupval(L); +    cl->l.upvals[i] = up; +    luaC_objbarrier(L, cl, up);    } -  setptvalue2s(L, L->top, tf); -  incr_top(L); -  cl = luaF_newLclosure(L, tf); -  setclLvalue(L, L->top - 1, cl); -  for (i = 0; i < tf->sizeupvalues; i++)  /* initialize upvalues */ -    cl->l.upvals[i] = luaF_newupval(L);  } diff --git a/lua/ldump.c b/lua/ldump.c index 699e1dc..d5e6a47 100644 --- a/lua/ldump.c +++ b/lua/ldump.c @@ -1,5 +1,5 @@  /* -** $Id: ldump.c,v 1.19 2011/11/23 17:48:18 lhf Exp $ +** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $  ** save precompiled Lua chunks  ** See Copyright Notice in lua.h  */ @@ -84,8 +84,8 @@ static void DumpConstants(const Proto* f, DumpState* D)   for (i=0; i<n; i++)   {    const TValue* o=&f->k[i]; -  DumpChar(ttype(o),D); -  switch (ttype(o)) +  DumpChar(ttypenv(o),D); +  switch (ttypenv(o))    {     case LUA_TNIL:  	break; @@ -98,6 +98,7 @@ static void DumpConstants(const Proto* f, DumpState* D)     case LUA_TSTRING:  	DumpString(rawtsvalue(o),D);  	break; +    default: lua_assert(0);    }   }   n=f->sizep; diff --git a/lua/lfunc.c b/lua/lfunc.c index 1a1a8bb..4fd27fe 100644 --- a/lua/lfunc.c +++ b/lua/lfunc.c @@ -1,5 +1,5 @@  /* -** $Id: lfunc.c,v 2.27 2010/06/30 14:11:17 roberto Exp $ +** $Id: lfunc.c,v 2.29 2012/05/08 13:53:33 roberto Exp $  ** Auxiliary functions to manipulate prototypes and closures  ** See Copyright Notice in lua.h  */ @@ -21,18 +21,15 @@  Closure *luaF_newCclosure (lua_State *L, int n) { -  Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl; -  c->c.isC = 1; +  Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;    c->c.nupvalues = cast_byte(n);    return c;  } -Closure *luaF_newLclosure (lua_State *L, Proto *p) { -  int n = p->sizeupvalues; -  Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; -  c->l.isC = 0; -  c->l.p = p; +Closure *luaF_newLclosure (lua_State *L, int n) { +  Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; +  c->l.p = NULL;    c->l.nupvalues = cast_byte(n);    while (n--) c->l.upvals[n] = NULL;    return c; @@ -146,13 +143,6 @@ void luaF_freeproto (lua_State *L, Proto *f) {  } -void luaF_freeclosure (lua_State *L, Closure *c) { -  int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : -                          sizeLclosure(c->l.nupvalues); -  luaM_freemem(L, c, size); -} - -  /*  ** Look for n-th local variable at line `line' in function `func'.  ** Returns NULL if not found. diff --git a/lua/lfunc.h b/lua/lfunc.h index da18923..e236a71 100644 --- a/lua/lfunc.h +++ b/lua/lfunc.h @@ -1,5 +1,5 @@  /* -** $Id: lfunc.h,v 2.6 2010/06/04 13:06:15 roberto Exp $ +** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $  ** Auxiliary functions to manipulate prototypes and closures  ** See Copyright Notice in lua.h  */ @@ -20,12 +20,11 @@  LUAI_FUNC Proto *luaF_newproto (lua_State *L);  LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);  LUAI_FUNC UpVal *luaF_newupval (lua_State *L);  LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);  LUAI_FUNC void luaF_close (lua_State *L, StkId level);  LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);  LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);  LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,                                           int pc); @@ -1,5 +1,5 @@  /* -** $Id: lgc.c,v 2.116 2011/12/02 13:18:41 roberto Exp $ +** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $  ** Garbage Collector  ** See Copyright Notice in lua.h  */ @@ -24,34 +24,40 @@ -/* how much to allocate before next GC step */ -#define GCSTEPSIZE	1024 +/* +** cost of sweeping one element (the size of a small object divided +** by some adjust for the sweep speed) +*/ +#define GCSWEEPCOST	((sizeof(TString) + 4) / 4)  /* maximum number of elements to sweep in each single step */ -#define GCSWEEPMAX	40 - -/* cost of sweeping one element */ -#define GCSWEEPCOST	1 +#define GCSWEEPMAX	(cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))  /* maximum number of finalizers to call in each GC step */  #define GCFINALIZENUM	4 -/* cost of marking the root set */ -#define GCROOTCOST	10 -/* cost of atomic step */ -#define GCATOMICCOST	1000 +/* +** macro to adjust 'stepmul': 'stepmul' is actually used like +** 'stepmul / STEPMULADJ' (value chosen by tests) +*/ +#define STEPMULADJ		200 + +/* +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) +*/ +#define PAUSEADJ		200 + -/* basic cost to traverse one object (to be added to the links the -   object may have) */ -#define TRAVCOST	5  /*  ** standard negative debt for GC; a reasonable "time" to wait before  ** starting a new cycle  */ -#define stddebt(g)	(-cast(l_mem, gettotalbytes(g)/100) * g->gcpause) +#define stddebtest(g,e)	(-cast(l_mem, (e)/PAUSEADJ) * g->gcpause) +#define stddebt(g)	stddebtest(g, gettotalbytes(g))  /* @@ -65,8 +71,6 @@  #define white2gray(x)	resetbits(gch(x)->marked, WHITEBITS)  #define black2gray(x)	resetbit(gch(x)->marked, BLACKBIT) -#define stringmark(s)	((void)((s) && resetbits((s)->tsv.marked, WHITEBITS))) -  #define isfinalized(x)		testbit(gch(x)->marked, FINALIZEDBIT) @@ -123,10 +127,10 @@ static void removeentry (Node *n) {  ** other objects: if really collected, cannot keep them; for objects  ** being finalized, keep them in keys, but not in values  */ -static int iscleared (const TValue *o) { +static int iscleared (global_State *g, const TValue *o) {    if (!iscollectable(o)) return 0;    else if (ttisstring(o)) { -    stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */ +    markobject(g, rawtsvalue(o));  /* strings are `values', so are never weak */      return 0;    }    else return iswhite(gcvalue(o)); @@ -217,7 +221,8 @@ void luaC_checkupvalcolor (global_State *g, UpVal *uv) {  GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,                         int offset) {    global_State *g = G(L); -  GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); +  char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); +  GCObject *o = obj2gco(raw + offset);    if (list == NULL)      list = &g->allgc;  /* standard list for collectable objects */    gch(o)->marked = luaC_white(g); @@ -239,54 +244,63 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,  /* -** mark an object. Userdata and closed upvalues are visited and turned -** black here. Strings remain gray (it is the same as making them -** black). Other objects are marked gray and added to appropriate list -** to be visited (and turned black) later. (Open upvalues are already -** linked in 'headuv' list.) +** mark an object. Userdata, strings, and closed upvalues are visited +** and turned black here. Other objects are marked gray and added +** to appropriate list to be visited (and turned black) later. (Open +** upvalues are already linked in 'headuv' list.)  */  static void reallymarkobject (global_State *g, GCObject *o) { -  lua_assert(iswhite(o) && !isdead(g, o)); +  lu_mem size;    white2gray(o);    switch (gch(o)->tt) { -    case LUA_TSTRING: { -      return;  /* for strings, gray is as good as black */ +    case LUA_TSHRSTR: +    case LUA_TLNGSTR: { +      size = sizestring(gco2ts(o)); +      break;  /* nothing else to mark; make it black */      }      case LUA_TUSERDATA: {        Table *mt = gco2u(o)->metatable;        markobject(g, mt);        markobject(g, gco2u(o)->env); -      gray2black(o);  /* all pointers marked */ -      return; +      size = sizeudata(gco2u(o)); +      break;      }      case LUA_TUPVAL: {        UpVal *uv = gco2uv(o);        markvalue(g, uv->v); -      if (uv->v == &uv->u.value)  /* closed? (open upvalues remain gray) */ -        gray2black(o);  /* make it black */ +      if (uv->v != &uv->u.value)  /* open? */ +        return;  /* open upvalues remain gray */ +      size = sizeof(UpVal); +      break; +    } +    case LUA_TLCL: { +      gco2lcl(o)->gclist = g->gray; +      g->gray = o;        return;      } -    case LUA_TFUNCTION: { -      gco2cl(o)->c.gclist = g->gray; +    case LUA_TCCL: { +      gco2ccl(o)->gclist = g->gray;        g->gray = o; -      break; +      return;      }      case LUA_TTABLE: {        linktable(gco2t(o), &g->gray); -      break; +      return;      }      case LUA_TTHREAD: {        gco2th(o)->gclist = g->gray;        g->gray = o; -      break; +      return;      }      case LUA_TPROTO: {        gco2p(o)->gclist = g->gray;        g->gray = o; -      break; +      return;      } -    default: lua_assert(0); +    default: lua_assert(0); return;    } +  gray2black(o); +  g->GCmemtrav += size;  } @@ -359,7 +373,7 @@ static void traverseweakvalue (global_State *g, Table *h) {      else {        lua_assert(!ttisnil(gkey(n)));        markvalue(g, gkey(n));  /* mark key */ -      if (!hasclears && iscleared(gval(n)))  /* is there a white value? */ +      if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */          hasclears = 1;  /* table will have to be cleared */      }    } @@ -388,7 +402,7 @@ static int traverseephemeron (global_State *g, Table *h) {      checkdeadkey(n);      if (ttisnil(gval(n)))  /* entry is empty? */        removeentry(n);  /* remove it */ -    else if (iscleared(gkey(n))) {  /* key is not marked (yet)? */ +    else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */        hasclears = 1;  /* table must be cleared */        if (valiswhite(gval(n)))  /* value not marked yet? */          prop = 1;  /* must propagate again */ @@ -426,30 +440,26 @@ static void traversestrongtable (global_State *g, Table *h) {  } -static int traversetable (global_State *g, Table *h) { +static lu_mem traversetable (global_State *g, Table *h) { +  const char *weakkey, *weakvalue;    const TValue *mode = gfasttm(g, h->metatable, TM_MODE);    markobject(g, h->metatable); -  if (mode && ttisstring(mode)) {  /* is there a weak mode? */ -    int weakkey = (strchr(svalue(mode), 'k') != NULL); -    int weakvalue = (strchr(svalue(mode), 'v') != NULL); -    if (weakkey || weakvalue) {  /* is really weak? */ -      black2gray(obj2gco(h));  /* keep table gray */ -      if (!weakkey) {  /* strong keys? */ -        traverseweakvalue(g, h); -        return TRAVCOST + sizenode(h); -      } -      else if (!weakvalue) {  /* strong values? */ -        traverseephemeron(g, h); -        return TRAVCOST + h->sizearray + sizenode(h); -      } -      else { -        linktable(h, &g->allweak);  /* nothing to traverse now */ -        return TRAVCOST; -      } -    }  /* else go through */ +  if (mode && ttisstring(mode) &&  /* is there a weak mode? */ +      ((weakkey = strchr(svalue(mode), 'k')), +       (weakvalue = strchr(svalue(mode), 'v')), +       (weakkey || weakvalue))) {  /* is really weak? */ +    black2gray(obj2gco(h));  /* keep table gray */ +    if (!weakkey)  /* strong keys? */ +      traverseweakvalue(g, h); +    else if (!weakvalue)  /* strong values? */ +      traverseephemeron(g, h); +    else  /* all weak */ +      linktable(h, &g->allweak);  /* nothing to traverse now */    } -  traversestrongtable(g, h); -  return TRAVCOST + h->sizearray + (2 * sizenode(h)); +  else  /* not weak */ +    traversestrongtable(g, h); +  return sizeof(Table) + sizeof(TValue) * h->sizearray + +                         sizeof(Node) * sizenode(h);  } @@ -457,86 +467,101 @@ static int traverseproto (global_State *g, Proto *f) {    int i;    if (f->cache && iswhite(obj2gco(f->cache)))      f->cache = NULL;  /* allow cache to be collected */ -  stringmark(f->source); +  markobject(g, 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 */ -    stringmark(f->upvalues[i].name); +    markobject(g, f->upvalues[i].name);    for (i = 0; i < f->sizep; i++)  /* mark nested protos */      markobject(g, f->p[i]);    for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */ -    stringmark(f->locvars[i].varname); -  return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; +    markobject(g, f->locvars[i].varname); +  return sizeof(Proto) + sizeof(Instruction) * f->sizecode + +                         sizeof(Proto *) * f->sizep + +                         sizeof(TValue) * f->sizek + +                         sizeof(int) * f->sizelineinfo + +                         sizeof(LocVar) * f->sizelocvars + +                         sizeof(Upvaldesc) * f->sizeupvalues;  } -static int traverseclosure (global_State *g, Closure *cl) { -  if (cl->c.isC) { -    int i; -    for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */ -      markvalue(g, &cl->c.upvalue[i]); -  } -  else { -    int i; -    lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); -    markobject(g, cl->l.p);  /* mark its prototype */ -    for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */ -      markobject(g, cl->l.upvals[i]); -  } -  return TRAVCOST + cl->c.nupvalues; +static lu_mem traverseCclosure (global_State *g, CClosure *cl) { +  int i; +  for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */ +    markvalue(g, &cl->upvalue[i]); +  return sizeCclosure(cl->nupvalues); +} + +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { +  int i; +  markobject(g, cl->p);  /* mark its prototype */ +  for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */ +    markobject(g, cl->upvals[i]); +  return sizeLclosure(cl->nupvalues);  } -static int traversestack (global_State *g, lua_State *L) { -  StkId o = L->stack; +static lu_mem traversestack (global_State *g, lua_State *th) { +  StkId o = th->stack;    if (o == NULL)      return 1;  /* stack not completely built yet */ -  for (; o < L->top; o++) +  for (; o < th->top; o++)      markvalue(g, o);    if (g->gcstate == GCSatomic) {  /* final traversal? */ -    StkId lim = L->stack + L->stacksize;  /* real end of stack */ +    StkId lim = th->stack + th->stacksize;  /* real end of stack */      for (; o < lim; o++)  /* clear not-marked stack slice */        setnilvalue(o);    } -  return TRAVCOST + cast_int(o - L->stack); +  return sizeof(lua_State) + sizeof(TValue) * th->stacksize;  }  /*  ** traverse one gray object, turning it to black (except for threads,  ** which are always gray). -** Returns number of values traversed.  */ -static int propagatemark (global_State *g) { +static void propagatemark (global_State *g) { +  lu_mem size;    GCObject *o = g->gray;    lua_assert(isgray(o));    gray2black(o);    switch (gch(o)->tt) {      case LUA_TTABLE: {        Table *h = gco2t(o); -      g->gray = h->gclist; -      return traversetable(g, h); +      g->gray = h->gclist;  /* remove from 'gray' list */ +      size = traversetable(g, h); +      break; +    } +    case LUA_TLCL: { +      LClosure *cl = gco2lcl(o); +      g->gray = cl->gclist;  /* remove from 'gray' list */ +      size = traverseLclosure(g, cl); +      break;      } -    case LUA_TFUNCTION: { -      Closure *cl = gco2cl(o); -      g->gray = cl->c.gclist; -      return traverseclosure(g, cl); +    case LUA_TCCL: { +      CClosure *cl = gco2ccl(o); +      g->gray = cl->gclist;  /* remove from 'gray' list */ +      size = traverseCclosure(g, cl); +      break;      }      case LUA_TTHREAD: {        lua_State *th = gco2th(o); -      g->gray = th->gclist; +      g->gray = th->gclist;  /* remove from 'gray' list */        th->gclist = g->grayagain; -      g->grayagain = o; +      g->grayagain = o;  /* insert into 'grayagain' list */        black2gray(o); -      return traversestack(g, th); +      size = traversestack(g, th); +      break;      }      case LUA_TPROTO: {        Proto *p = gco2p(o); -      g->gray = p->gclist; -      return traverseproto(g, p); +      g->gray = p->gclist;  /* remove from 'gray' list */ +      size = traverseproto(g, p); +      break;      } -    default: lua_assert(0); return 0; +    default: lua_assert(0); return;    } +  g->GCmemtrav += size;  } @@ -599,12 +624,12 @@ static void convergeephemerons (global_State *g) {  ** clear entries with unmarked keys from all weaktables in list 'l' up  ** to element 'f'  */ -static void clearkeys (GCObject *l, GCObject *f) { +static void clearkeys (global_State *g, GCObject *l, GCObject *f) {    for (; l != f; l = gco2t(l)->gclist) {      Table *h = gco2t(l);      Node *n, *limit = gnodelast(h);      for (n = gnode(h, 0); n < limit; n++) { -      if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) { +      if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {          setnilvalue(gval(n));  /* remove value ... */          removeentry(n);  /* and remove entry from table */        } @@ -617,18 +642,18 @@ static void clearkeys (GCObject *l, GCObject *f) {  ** clear entries with unmarked values from all weaktables in list 'l' up  ** to element 'f'  */ -static void clearvalues (GCObject *l, GCObject *f) { +static void clearvalues (global_State *g, GCObject *l, GCObject *f) {    for (; l != f; l = gco2t(l)->gclist) {      Table *h = gco2t(l);      Node *n, *limit = gnodelast(h);      int i;      for (i = 0; i < h->sizearray; i++) {        TValue *o = &h->array[i]; -      if (iscleared(o))  /* value was collected? */ +      if (iscleared(g, o))  /* value was collected? */          setnilvalue(o);  /* remove value */      }      for (n = gnode(h, 0); n < limit; n++) { -      if (!ttisnil(gval(n)) && iscleared(gval(n))) { +      if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {          setnilvalue(gval(n));  /* remove value ... */          removeentry(n);  /* and remove entry from table */        } @@ -640,13 +665,22 @@ static void clearvalues (GCObject *l, GCObject *f) {  static void freeobj (lua_State *L, GCObject *o) {    switch (gch(o)->tt) {      case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; -    case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; +    case LUA_TLCL: { +      luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); +      break; +    } +    case LUA_TCCL: { +      luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); +      break; +    }      case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;      case LUA_TTABLE: luaH_free(L, gco2t(o)); break;      case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;      case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; -    case LUA_TSTRING: { +    case LUA_TSHRSTR:        G(L)->strt.nuse--; +      /* go through */ +    case LUA_TLNGSTR: {        luaM_freemem(L, o, sizestring(gco2ts(o)));        break;      } @@ -689,7 +723,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {    int ow = otherwhite(g);    int toclear, toset;  /* bits to clear and to set in all live objects */    int tostop;  /* stop sweep when this is true */ -  l_mem debt = g->GCdebt;  /* current debt */    if (isgenerational(g)) {  /* generational mode? */      toclear = ~0;  /* clear nothing */      toset = bitmask(OLDBIT);  /* set the old bit of all surviving objects */ @@ -708,19 +741,30 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {        freeobj(L, curr);  /* erase 'curr' */      }      else { +      if (testbits(marked, tostop)) +        return NULL;  /* stop sweeping this list */        if (gch(curr)->tt == LUA_TTHREAD)          sweepthread(L, gco2th(curr));  /* sweep thread's upvalues */ -      if (testbits(marked, tostop)) { -        static GCObject *nullp = NULL; -        p = &nullp;  /* stop sweeping this list */ -        break; -      }        /* update marks */        gch(curr)->marked = cast_byte((marked & toclear) | toset);        p = &gch(curr)->next;  /* go to next element */      }    } -  luaE_setdebt(g, debt);  /* sweeping should not change debt */ +  return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { +  GCObject ** old = p; +  int i = 0; +  do { +    i++; +    p = sweeplist(L, p, 1); +  } while (p == old); +  if (n) *n += i;    return p;  } @@ -783,12 +827,14 @@ static void GCTM (lua_State *L, int propagateerrors) {      L->allowhook = oldah;  /* restore hooks */      g->gcrunning = running;  /* restore state */      if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */ -      if (status == LUA_ERRRUN) {  /* is there an error msg.? */ -        luaO_pushfstring(L, "error in __gc metamethod (%s)", -                                        lua_tostring(L, -1)); +      if (status == LUA_ERRRUN) {  /* is there an error object? */ +        const char *msg = (ttisstring(L->top - 1)) +                            ? svalue(L->top - 1) +                            : "no message"; +        luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);          status = LUA_ERRGCMM;  /* error in __gc metamethod */        } -      luaD_throw(L, status);  /* re-send error */ +      luaD_throw(L, status);  /* re-throw error */      }    }  } @@ -834,12 +880,21 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {      return;  /* nothing to be done */    else {  /* move 'o' to 'finobj' list */      GCObject **p; -    for (p = &g->allgc; *p != o; p = &gch(*p)->next) ; -    *p = gch(o)->next;  /* remove 'o' from root list */ -    gch(o)->next = g->finobj;  /* link it in list 'finobj' */ +    GCheader *ho = gch(o); +    if (g->sweepgc == &ho->next) {  /* avoid removing current sweep object */ +      lua_assert(issweepphase(g)); +      g->sweepgc = sweeptolive(L, g->sweepgc, NULL); +    } +    /* search for pointer pointing to 'o' */ +    for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } +    *p = ho->next;  /* remove 'o' from root list */ +    ho->next = g->finobj;  /* link it in list 'finobj' */      g->finobj = o; -    l_setbit(gch(o)->marked, SEPARATED);  /* mark it as such */ -    resetoldbit(o);  /* see MOVE OLD rule */ +    l_setbit(ho->marked, SEPARATED);  /* mark it as such */ +    if (!keepinvariant(g))  /* not keeping invariant? */ +      makewhite(g, o);  /* "sweep" object */ +    else +      resetoldbit(o);  /* see MOVE OLD rule */    }  } @@ -856,6 +911,28 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {  #define sweepphases  \  	(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + +/* +** enter first sweep phase (strings) and prepare pointers for other +** sweep phases.  The calls to 'sweeptolive' make pointers point to an +** object inside the list (instead of to the header), so that the real +** sweep do not need to skip objects created between "now" and the start +** of the real sweep. +** Returns how many objects it sweeped. +*/ +static int entersweep (lua_State *L) { +  global_State *g = G(L); +  int n = 0; +  g->gcstate = GCSsweepstring; +  lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); +  /* prepare to sweep strings, finalizable objects, and regular objects */ +  g->sweepstrgc = 0; +  g->sweepfin = sweeptolive(L, &g->finobj, &n); +  g->sweepgc = sweeptolive(L, &g->allgc, &n); +  return n; +} + +  /*  ** change GC mode  */ @@ -865,15 +942,14 @@ void luaC_changemode (lua_State *L, int mode) {    if (mode == KGC_GEN) {  /* change to generational mode */      /* make sure gray lists are consistent */      luaC_runtilstate(L, bitmask(GCSpropagate)); -    g->lastmajormem = gettotalbytes(g); +    g->GCestimate = gettotalbytes(g);      g->gckind = KGC_GEN;    }    else {  /* change to incremental mode */      /* sweep all objects to turn them back to white         (as white has not changed, nothing extra will be collected) */ -    g->sweepstrgc = 0; -    g->gcstate = GCSsweepstring;      g->gckind = KGC_NORMAL; +    entersweep(L);      luaC_runtilstate(L, ~sweepphases);    }  } @@ -907,8 +983,9 @@ void luaC_freeallobjects (lua_State *L) {  } -static void atomic (lua_State *L) { +static l_mem atomic (lua_State *L) {    global_State *g = G(L); +  l_mem work = -g->GCmemtrav;  /* start counting work */    GCObject *origweak, *origall;    lua_assert(!iswhite(obj2gco(g->mainthread)));    markobject(g, L);  /* mark running thread */ @@ -917,77 +994,87 @@ static void atomic (lua_State *L) {    markmt(g);  /* mark basic metatables */    /* remark occasional upvalues of (maybe) dead threads */    remarkupvals(g); +  propagateall(g);  /* propagate changes */ +  work += g->GCmemtrav;  /* stop counting (do not (re)count grays) */    /* traverse objects caught by write barrier and by 'remarkupvals' */    retraversegrays(g); +  work -= g->GCmemtrav;  /* restart counting */    convergeephemerons(g);    /* at this point, all strongly accessible objects are marked. */    /* clear values from weak tables, before checking finalizers */ -  clearvalues(g->weak, NULL); -  clearvalues(g->allweak, NULL); +  clearvalues(g, g->weak, NULL); +  clearvalues(g, g->allweak, NULL);    origweak = g->weak; origall = g->allweak; +  work += g->GCmemtrav;  /* stop counting (objects being finalized) */    separatetobefnz(L, 0);  /* separate objects to be finalized */ -  markbeingfnz(g);  /* mark userdata that will be finalized */ +  markbeingfnz(g);  /* mark objects that will be finalized */    propagateall(g);  /* remark, to propagate `preserveness' */ +  work -= g->GCmemtrav;  /* restart counting */    convergeephemerons(g);    /* at this point, all resurrected objects are marked. */    /* remove dead objects from weak tables */ -  clearkeys(g->ephemeron, NULL);  /* clear keys from all ephemeron tables */ -  clearkeys(g->allweak, NULL);  /* clear keys from all allweak tables */ +  clearkeys(g, g->ephemeron, NULL);  /* clear keys from all ephemeron tables */ +  clearkeys(g, g->allweak, NULL);  /* clear keys from all allweak tables */    /* clear values from resurrected weak tables */ -  clearvalues(g->weak, origweak); -  clearvalues(g->allweak, origall); -  g->sweepstrgc = 0;  /* prepare to sweep strings */ -  g->gcstate = GCSsweepstring; +  clearvalues(g, g->weak, origweak); +  clearvalues(g, g->allweak, origall);    g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */ -  /*lua_checkmemory(L);*/ +  work += g->GCmemtrav;  /* complete counting */ +  return work;  /* estimate of memory marked by 'atomic' */  } -static l_mem singlestep (lua_State *L) { +static lu_mem singlestep (lua_State *L) {    global_State *g = G(L);    switch (g->gcstate) {      case GCSpause: { +      g->GCmemtrav = 0;  /* start to count memory traversed */        if (!isgenerational(g))          markroot(g);  /* start a new collection */ -      /* in any case, root must be marked */ +      /* in any case, root must be marked at this point */        lua_assert(!iswhite(obj2gco(g->mainthread))                && !iswhite(gcvalue(&g->l_registry)));        g->gcstate = GCSpropagate; -      return GCROOTCOST; +      return g->GCmemtrav;      }      case GCSpropagate: { -      if (g->gray) -        return propagatemark(g); +      if (g->gray) { +        lu_mem oldtrav = g->GCmemtrav; +        propagatemark(g); +        return g->GCmemtrav - oldtrav;  /* memory traversed in this step */ +      }        else {  /* no more `gray' objects */ +        lu_mem work; +        int sw;          g->gcstate = GCSatomic;  /* finish mark phase */ -        atomic(L); -        return GCATOMICCOST; +        g->GCestimate = g->GCmemtrav;  /* save what was counted */; +        work = atomic(L);  /* add what was traversed by 'atomic' */ +        g->GCestimate += work;  /* estimate of total memory traversed */  +        sw = entersweep(L); +        return work + sw * GCSWEEPCOST;        }      }      case GCSsweepstring: { -      if (g->sweepstrgc < g->strt.size) { -        sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); -        return GCSWEEPCOST; -      } -      else {  /* no more strings to sweep */ -        g->sweepgc = &g->finobj;  /* prepare to sweep finalizable objects */ +      int i; +      for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++) +        sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]); +      g->sweepstrgc += i; +      if (g->sweepstrgc >= g->strt.size)  /* no more strings to sweep? */          g->gcstate = GCSsweepudata; -        return 0; -      } +      return i * GCSWEEPCOST;      }      case GCSsweepudata: { -      if (*g->sweepgc) { -        g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); +      if (g->sweepfin) { +        g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);          return GCSWEEPMAX*GCSWEEPCOST;        }        else { -        g->sweepgc = &g->allgc;  /* go to next phase */          g->gcstate = GCSsweep; -        return GCSWEEPCOST; +        return 0;        }      }      case GCSsweep: { -      if (*g->sweepgc) { +      if (g->sweepgc) {          g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);          return GCSWEEPMAX*GCSWEEPCOST;        } @@ -1018,43 +1105,52 @@ void luaC_runtilstate (lua_State *L, int statesmask) {  static void generationalcollection (lua_State *L) {    global_State *g = G(L); -  if (g->lastmajormem == 0) {  /* signal for another major collection? */ +  if (g->GCestimate == 0) {  /* signal for another major collection? */      luaC_fullgc(L, 0);  /* perform a full regular collection */ -    g->lastmajormem = gettotalbytes(g);  /* update control */ +    g->GCestimate = gettotalbytes(g);  /* update control */    }    else { +    lu_mem estimate = g->GCestimate;      luaC_runtilstate(L, ~bitmask(GCSpause));  /* run complete cycle */      luaC_runtilstate(L, bitmask(GCSpause)); -    if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc) -      g->lastmajormem = 0;  /* signal for a major collection */ +    if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) +      g->GCestimate = 0;  /* signal for a major collection */    }    luaE_setdebt(g, stddebt(g));  } -static void step (lua_State *L) { +static void incstep (lua_State *L) {    global_State *g = G(L); -  l_mem lim = g->gcstepmul;  /* how much to work */ +  l_mem debt = g->GCdebt; +  int stepmul = g->gcstepmul; +  if (stepmul < 40) stepmul = 40;  /* avoid ridiculous low values */ +  /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ +  debt = (debt / STEPMULADJ) + 1; +  debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;    do {  /* always perform at least one single step */ -    lim -= singlestep(L); -  } while (lim > 0 && g->gcstate != GCSpause); -  if (g->gcstate != GCSpause) -    luaE_setdebt(g, g->GCdebt - GCSTEPSIZE); +    lu_mem work = singlestep(L);  /* do some work */ +    debt -= work; +  } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); +  if (g->gcstate == GCSpause) +    debt = stddebtest(g, g->GCestimate);  /* pause until next cycle */    else -    luaE_setdebt(g, stddebt(g)); +    debt = (debt / stepmul) * STEPMULADJ;  /* convert 'work units' to Kb */ +  luaE_setdebt(g, debt);  }  /* -** performs a basic GC step even if the collector is stopped +** performs a basic GC step  */  void luaC_forcestep (lua_State *L) {    global_State *g = G(L);    int i;    if (isgenerational(g)) generationalcollection(L); -  else step(L); -  for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++) -    GCTM(L, 1);  /* Call a few pending finalizers */ +  else incstep(L); +  /* run a few finalizers (or all of them at the end of a collect cycle) */ +  for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) +    GCTM(L, 1);  /* call one finalizer */  } @@ -1062,10 +1158,13 @@ void luaC_forcestep (lua_State *L) {  ** performs a basic GC step only if collector is running  */  void luaC_step (lua_State *L) { -  if (G(L)->gcrunning) luaC_forcestep(L); +  global_State *g = G(L); +  if (g->gcrunning) luaC_forcestep(L); +  else luaE_setdebt(g, -GCSTEPSIZE);  /* avoid being called too often */  } +  /*  ** performs a full GC cycle; if "isemergency", does not call  ** finalizers (which could change stack positions) @@ -1073,16 +1172,19 @@ void luaC_step (lua_State *L) {  void luaC_fullgc (lua_State *L, int isemergency) {    global_State *g = G(L);    int origkind = g->gckind; +  int someblack = keepinvariant(g);    lua_assert(origkind != KGC_EMERGENCY); -  if (!isemergency)   /* do not run finalizers during emergency GC */ +  if (isemergency)  /* do not run finalizers during emergency GC */ +    g->gckind = KGC_EMERGENCY; +  else { +    g->gckind = KGC_NORMAL;      callallpendingfinalizers(L, 1); -  if (keepinvariant(g)) {  /* marking phase? */ +  } +  if (someblack) {  /* may there be some black objects? */      /* must sweep all objects to turn them back to white         (as white has not changed, nothing will be collected) */ -    g->sweepstrgc = 0; -    g->gcstate = GCSsweepstring; +    entersweep(L);    } -  g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL;    /* finish any pending sweep phase to start a new cycle */    luaC_runtilstate(L, bitmask(GCSpause));    /* run entire collector */ @@ -1,5 +1,5 @@  /* -** $Id: lgc.h,v 2.52 2011/10/03 17:54:25 roberto Exp $ +** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $  ** Garbage Collector  ** See Copyright Notice in lua.h  */ @@ -25,6 +25,14 @@  */ + +/* how much to allocate before next GC step */ +#if !defined(GCSTEPSIZE) +/* ~100 small strings */ +#define GCSTEPSIZE	(cast_int(100 * sizeof(TString))) +#endif + +  /*  ** Possible states of the Garbage Collector  */ @@ -1,5 +1,5 @@  /* -** $Id: llex.c,v 2.59 2011/11/30 12:43:51 roberto Exp $ +** $Id: llex.c,v 2.61 2012/01/23 23:05:51 roberto Exp $  ** Lexical Analyzer  ** See Copyright Notice in lua.h  */ @@ -67,7 +67,7 @@ void luaX_init (lua_State *L) {    for (i=0; i<NUM_RESERVED; i++) {      TString *ts = luaS_new(L, luaX_tokens[i]);      luaS_fix(ts);  /* reserved words are never collected */ -    ts->tsv.reserved = cast_byte(i+1);  /* reserved word */ +    ts->tsv.extra = cast_byte(i+1);  /* reserved word */    }  } @@ -222,13 +222,24 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) {  /* LUA_NUMBER */ +/* +** this function is quite liberal in what it accepts, as 'luaO_str2d' +** will reject ill-formed numerals. +*/  static void read_numeral (LexState *ls, SemInfo *seminfo) { +  const char *expo = "Ee"; +  int first = ls->current;    lua_assert(lisdigit(ls->current)); -  do { -    save_and_next(ls); -    if (check_next(ls, "EePp"))  /* exponent part? */ +  save_and_next(ls); +  if (first == '0' && check_next(ls, "Xx"))  /* hexadecimal? */ +    expo = "Pp"; +  for (;;) { +    if (check_next(ls, expo))  /* exponent part? */        check_next(ls, "+-");  /* optional exponent sign */ -  } while (lislalnum(ls->current) || ls->current == '.'); +    if (lisxdigit(ls->current) || ls->current == '.') +      save_and_next(ls); +    else  break; +  }    save(ls, '\0');    buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */    if (!buff2d(ls->buff, &seminfo->r))  /* format error? */ @@ -480,8 +491,8 @@ static int llex (LexState *ls, SemInfo *seminfo) {            ts = luaX_newstring(ls, luaZ_buffer(ls->buff),                                    luaZ_bufflen(ls->buff));            seminfo->ts = ts; -          if (ts->tsv.reserved > 0)  /* reserved word? */ -            return ts->tsv.reserved - 1 + FIRST_RESERVED; +          if (isreserved(ts))  /* reserved word? */ +            return ts->tsv.extra - 1 + FIRST_RESERVED;            else {              return TK_NAME;            } diff --git a/lua/llimits.h b/lua/llimits.h index 48dc81f..fc9de1a 100644 --- a/lua/llimits.h +++ b/lua/llimits.h @@ -1,5 +1,5 @@  /* -** $Id: llimits.h,v 1.95 2011/12/06 16:58:36 roberto Exp $ +** $Id: llimits.h,v 1.99 2012/05/28 20:32:28 roberto Exp $  ** Limits, basic types, and some other `installation-dependent' definitions  ** See Copyright Notice in lua.h  */ @@ -31,6 +31,8 @@ typedef unsigned char lu_byte;  #define MAX_LUMEM	((lu_mem)(~(lu_mem)0)-2) +#define MAX_LMEM	((l_mem) ((MAX_LUMEM >> 1) - 2)) +  #define MAX_INT (INT_MAX-2)  /* maximum value of an int (-2 for safety) */ @@ -209,31 +211,36 @@ typedef lu_int32 Instruction;  #elif defined(LUA_IEEE754TRICK)		/* }{ */  /* the next trick should work on any machine using IEEE754 with -   a 32-bit integer type */ +   a 32-bit int type */  union luai_Cast { double l_d; LUA_INT32 l_p[2]; };  #if !defined(LUA_IEEEENDIAN)	/* { */  #define LUAI_EXTRAIEEE	\    static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIAN		(ieeeendian.l_p[1] == 33) +#define LUA_IEEEENDIANLOC	(ieeeendian.l_p[1] == 33)  #else +#define LUA_IEEEENDIANLOC	LUA_IEEEENDIAN  #define LUAI_EXTRAIEEE		/* empty */  #endif				/* } */  #define lua_number2int32(i,n,t) \    { LUAI_EXTRAIEEE \      volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ -    (i) = (t)u.l_p[LUA_IEEEENDIAN]; } +    (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }  #define luai_hashnum(i,n)  \    { volatile union luai_Cast u; u.l_d = (n) + 1.0;  /* avoid -0 */ \      (i) = u.l_p[0]; (i) += u.l_p[1]; }  /* add double bits for his hash */  #define lua_number2int(i,n)		lua_number2int32(i, n, int) -#define lua_number2integer(i,n)		lua_number2int32(i, n, lua_Integer)  #define lua_number2unsigned(i,n)	lua_number2int32(i, n, lua_Unsigned) +/* the trick can be expanded to lua_Integer when it is a 32-bit value */ +#if defined(LUA_IEEELL) +#define lua_number2integer(i,n)		lua_number2int32(i, n, lua_Integer) +#endif +  #endif				/* } */ diff --git a/lua/lmathlib.c b/lua/lmathlib.c index b17237f..c3c605e 100644 --- a/lua/lmathlib.c +++ b/lua/lmathlib.c @@ -1,5 +1,5 @@  /* -** $Id: lmathlib.c,v 1.80 2011/07/05 12:49:35 roberto Exp $ +** $Id: lmathlib.c,v 1.81 2012/05/18 17:47:53 roberto Exp $  ** Standard mathematical library  ** See Copyright Notice in lua.h  */ @@ -17,17 +17,17 @@  #include "lualib.h" -#undef PI -#define PI (3.14159265358979323846) -#define RADIANS_PER_DEGREE (PI/180.0) - -  /* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */  #if !defined(l_tg)  #define l_tg(x)		(x)  #endif +#undef PI +#define PI (l_tg(3.1415926535897932384626433832795)) +#define RADIANS_PER_DEGREE (PI/180.0) + +  static int math_abs (lua_State *L) {    lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); @@ -1,5 +1,5 @@  /* -** $Id: lmem.c,v 1.83 2011/11/30 12:42:49 roberto Exp $ +** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $  ** Interface to Memory Manager  ** See Copyright Notice in lua.h  */ @@ -94,22 +94,6 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {    }    lua_assert((nsize == 0) == (newblock == NULL));    g->GCdebt = (g->GCdebt + nsize) - realosize; -#if defined(TRACEMEM) -  { /* auxiliary patch to monitor garbage collection. -    ** To plot, gnuplot with following command: -    ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines -    */ -    static unsigned long total = 0;  /* our "time" */ -    static FILE *f = NULL;  /* output file */ -    total++;  /* "time" always grows */ -    if ((total % 200) == 0) { -      if (f == NULL) f = fopen(TRACEMEM, "w"); -      fprintf(f, "%lu %u %d %d\n", total, -              gettotalbytes(g), g->GCdebt, g->gcstate * 10000); -    } -  } -#endif -    return newblock;  } diff --git a/lua/loadlib.c b/lua/loadlib.c index 783bc12..a995927 100644 --- a/lua/loadlib.c +++ b/lua/loadlib.c @@ -1,5 +1,5 @@  /* -** $Id: loadlib.c,v 1.108 2011/12/12 16:34:03 roberto Exp $ +** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 roberto Exp $  ** Dynamic library loader for Lua  ** See Copyright Notice in lua.h  ** @@ -92,9 +92,9 @@  #define LUA_OFSEP	"_" -#define LIBPREFIX	"LOADLIB: " +/* table (in the registry) that keeps handles for all loaded C libraries */ +#define CLIBS		"_CLIBS" -#define POF		LUA_POF  #define LIB_FAIL	"open" @@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {  #endif - -static void **ll_register (lua_State *L, const char *path) { -  void **plib; -  lua_pushfstring(L, "%s%s", LIBPREFIX, path); -  lua_gettable(L, LUA_REGISTRYINDEX);  /* check library in registry? */ -  if (!lua_isnil(L, -1))  /* is there an entry? */ -    plib = (void **)lua_touserdata(L, -1); -  else {  /* no entry yet; create one */ -    lua_pop(L, 1);  /* remove result from gettable */ -    plib = (void **)lua_newuserdata(L, sizeof(const void *)); -    *plib = NULL; -    luaL_setmetatable(L, "_LOADLIB"); -    lua_pushfstring(L, "%s%s", LIBPREFIX, path); -    lua_pushvalue(L, -2); -    lua_settable(L, LUA_REGISTRYINDEX); -  } +static void *ll_checkclib (lua_State *L, const char *path) { +  void *plib; +  lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); +  lua_getfield(L, -1, path); +  plib = lua_touserdata(L, -1);  /* plib = CLIBS[path] */ +  lua_pop(L, 2);  /* pop CLIBS table and 'plib' */    return plib;  } +static void ll_addtoclib (lua_State *L, const char *path, void *plib) { +  lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); +  lua_pushlightuserdata(L, plib); +  lua_pushvalue(L, -1); +  lua_setfield(L, -3, path);  /* CLIBS[path] = plib */ +  lua_rawseti(L, -2, luaL_len(L, -2) + 1);  /* CLIBS[#CLIBS + 1] = plib */ +  lua_pop(L, 1);  /* pop CLIBS table */ +} + +  /* -** __gc tag method: calls library's `ll_unloadlib' function with the lib -** handle +** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib +** handles in list CLIBS  */  static int gctm (lua_State *L) { -  void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); -  if (*lib) ll_unloadlib(*lib); -  *lib = NULL;  /* mark library as closed */ +  int n = luaL_len(L, 1); +  for (; n >= 1; n--) {  /* for each handle, in reverse order */ +    lua_rawgeti(L, 1, n);  /* get handle CLIBS[n] */ +    ll_unloadlib(lua_touserdata(L, -1)); +    lua_pop(L, 1);  /* pop handle */ +  }    return 0;  }  static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { -  void **reg = ll_register(L, path); -  if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); -  if (*reg == NULL) return ERRLIB;  /* unable to load library */ +  void *reg = ll_checkclib(L, path);  /* check loaded C libraries */ +  if (reg == NULL) {  /* must load library? */ +    reg = ll_load(L, path, *sym == '*'); +    if (reg == NULL) return ERRLIB;  /* unable to load library */ +    ll_addtoclib(L, path, reg); +  }    if (*sym == '*') {  /* loading only library (no function)? */      lua_pushboolean(L, 1);  /* return 'true' */      return 0;  /* no errors */    }    else { -    lua_CFunction f = ll_sym(L, *reg, sym); +    lua_CFunction f = ll_sym(L, reg, sym);      if (f == NULL)        return ERRFUNC;  /* unable to find function */      lua_pushcfunction(L, f);  /* else create new function */ @@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {    if (mark) {      int stat;      funcname = lua_pushlstring(L, modname, mark - modname); -    funcname = lua_pushfstring(L, POF"%s", funcname); +    funcname = lua_pushfstring(L, LUA_POF"%s", funcname);      stat = ll_loadfunc(L, filename, funcname);      if (stat != ERRFUNC) return stat;      modname = mark + 1;  /* else go ahead and try old-style name */    } -  funcname = lua_pushfstring(L, POF"%s", modname); +  funcname = lua_pushfstring(L, LUA_POF"%s", modname);    return ll_loadfunc(L, filename, funcname);  } @@ -476,9 +482,9 @@ static void findloader (lua_State *L, const char *name) {    lua_getfield(L, lua_upvalueindex(1), "searchers");  /* will be at index 3 */    if (!lua_istable(L, 3))      luaL_error(L, LUA_QL("package.searchers") " must be a table"); -  /*  iterate over available seachers to find a loader */ +  /*  iterate over available searchers to find a loader */    for (i = 1; ; i++) { -    lua_rawgeti(L, 3, i);  /* get a seacher */ +    lua_rawgeti(L, 3, i);  /* get a searcher */      if (lua_isnil(L, -1)) {  /* no more searchers? */        lua_pop(L, 1);  /* remove nil */        luaL_pushresult(&msg);  /* create error message */ @@ -666,18 +672,10 @@ static const luaL_Reg ll_funcs[] = {  }; -static const lua_CFunction searchers[] = -  {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; - - -LUAMOD_API int luaopen_package (lua_State *L) { +static void createsearcherstable (lua_State *L) { +  static const lua_CFunction searchers[] = +    {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};    int i; -  /* create new type _LOADLIB */ -  luaL_newmetatable(L, "_LOADLIB"); -  lua_pushcfunction(L, gctm); -  lua_setfield(L, -2, "__gc"); -  /* create `package' table */ -  luaL_newlib(L, pk_funcs);    /* create 'searchers' table */    lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);    /* fill it with pre-defined searchers */ @@ -686,6 +684,19 @@ LUAMOD_API int luaopen_package (lua_State *L) {      lua_pushcclosure(L, searchers[i], 1);      lua_rawseti(L, -2, i+1);    } +} + + +LUAMOD_API int luaopen_package (lua_State *L) { +  /* create table CLIBS to keep track of loaded C libraries */ +  luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); +  lua_createtable(L, 0, 1);  /* metatable for CLIBS */ +  lua_pushcfunction(L, gctm); +  lua_setfield(L, -2, "__gc");  /* set finalizer for CLIBS table */ +  lua_setmetatable(L, -2); +  /* create `package' table */ +  luaL_newlib(L, pk_funcs); +  createsearcherstable(L);  #if defined(LUA_COMPAT_LOADERS)    lua_pushvalue(L, -1);  /* make a copy of 'searchers' table */    lua_setfield(L, -3, "loaders");  /* put it in field `loaders' */ diff --git a/lua/lobject.h b/lua/lobject.h index 06246bf..ca75a02 100644 --- a/lua/lobject.h +++ b/lua/lobject.h @@ -1,5 +1,5 @@  /* -** $Id: lobject.h,v 2.64 2011/10/31 17:48:22 roberto Exp $ +** $Id: lobject.h,v 2.70 2012/05/11 14:10:50 roberto Exp $  ** Type definitions for Lua objects  ** See Copyright Notice in lua.h  */ @@ -36,6 +36,9 @@  ** bit 6: whether value is collectable  */ +#define VARBITS		(3 << 4) + +  /*  ** LUA_TFUNCTION variants:  ** 0 - Lua function @@ -49,6 +52,12 @@  #define LUA_TCCL	(LUA_TFUNCTION | (2 << 4))  /* C closure */ +/* +** LUA_TSTRING variants */ +#define LUA_TSHRSTR	(LUA_TSTRING | (0 << 4))  /* short strings */ +#define LUA_TLNGSTR	(LUA_TSTRING | (1 << 4))  /* long strings */ + +  /* Bit mark for collectable types */  #define BIT_ISCOLLECTABLE	(1 << 6) @@ -109,23 +118,28 @@ typedef struct lua_TValue TValue;  /* raw type tag of a TValue */  #define rttype(o)	((o)->tt_) +/* tag with no variants (bits 0-3) */ +#define novariant(x)	((x) & 0x0F) +  /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */  #define ttype(o)	(rttype(o) & 0x3F) -  /* type tag of a TValue with no variants (bits 0-3) */ -#define ttypenv(o)	(rttype(o) & 0x0F) +#define ttypenv(o)	(novariant(rttype(o)))  /* Macros to test type */  #define checktag(o,t)		(rttype(o) == (t)) +#define checktype(o,t)		(ttypenv(o) == (t))  #define ttisnumber(o)		checktag((o), LUA_TNUMBER)  #define ttisnil(o)		checktag((o), LUA_TNIL)  #define ttisboolean(o)		checktag((o), LUA_TBOOLEAN)  #define ttislightuserdata(o)	checktag((o), LUA_TLIGHTUSERDATA) -#define ttisstring(o)		checktag((o), ctb(LUA_TSTRING)) +#define ttisstring(o)		checktype((o), LUA_TSTRING) +#define ttisshrstring(o)	checktag((o), ctb(LUA_TSHRSTR)) +#define ttislngstring(o)	checktag((o), ctb(LUA_TLNGSTR))  #define ttistable(o)		checktag((o), ctb(LUA_TTABLE)) -#define ttisfunction(o)		(ttypenv(o) == LUA_TFUNCTION) +#define ttisfunction(o)		checktype(o, LUA_TFUNCTION)  #define ttisclosure(o)		((rttype(o) & 0x1F) == LUA_TFUNCTION)  #define ttisCclosure(o)		checktag((o), ctb(LUA_TCCL))  #define ttisLclosure(o)		checktag((o), ctb(LUA_TLCL)) @@ -161,7 +175,7 @@ typedef struct lua_TValue TValue;  /* Macros for internal tests */ -#define righttt(obj)		(ttypenv(obj) == gcvalue(obj)->gch.tt) +#define righttt(obj)		(ttype(obj) == gcvalue(obj)->gch.tt)  #define checkliveness(g,obj) \  	lua_longassert(!iscollectable(obj) || \ @@ -193,7 +207,8 @@ typedef struct lua_TValue TValue;  #define setsvalue(L,obj,x) \    { TValue *io=(obj); \ -    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TSTRING)); \ +    TString *x_ = (x); \ +    val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \      checkliveness(G(L),io); }  #define setuvalue(L,obj,x) \ @@ -221,11 +236,6 @@ typedef struct lua_TValue TValue;      val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \      checkliveness(G(L),io); } -#define setptvalue(L,obj,x) \ -  { TValue *io=(obj); \ -    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \ -    checkliveness(G(L),io); } -  #define setdeadvalue(obj)	settt_(obj, LUA_TDEADKEY) @@ -256,6 +266,8 @@ typedef struct lua_TValue TValue;  #define setsvalue2n	setsvalue +/* check whether a number is valid (useful only for NaN trick) */ +#define luai_checknum(L,o,c)	{ /* empty */ }  /* @@ -263,10 +275,7 @@ typedef struct lua_TValue TValue;  ** NaN Trick  ** =======================================================  */ - -#if defined(LUA_NANTRICK) \ - || defined(LUA_NANTRICK_LE) \ - || defined(LUA_NANTRICK_BE) +#if defined(LUA_NANTRICK)  /*  ** numbers are represented in the 'd_' field. All other values have the @@ -274,15 +283,23 @@ typedef struct lua_TValue TValue;  ** a "signaled NaN", which is never generated by regular operations by  ** the CPU (nor by 'strtod')  */ -#if !defined(NNMARK) + +/* allows for external implementation for part of the trick */ +#if !defined(NNMARK)	/* { */ + + +#if !defined(LUA_IEEEENDIAN) +#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN' +#endif + +  #define NNMARK		0x7FF7A500  #define NNMASK		0x7FFFFF00 -#endif  #undef TValuefields  #undef NILCONSTANT -#if defined(LUA_NANTRICK_LE) +#if (LUA_IEEEENDIAN == 0)	/* { */  /* little endian */  #define TValuefields  \ @@ -293,7 +310,7 @@ typedef struct lua_TValue TValue;  #define d_(o)		((o)->u.d__)  #define tt_(o)		((o)->u.i.tt__) -#elif defined(LUA_NANTRICK_BE) +#else				/* }{ */  /* big endian */  #define TValuefields  \ @@ -304,10 +321,9 @@ typedef struct lua_TValue TValue;  #define d_(o)		((o)->u.d__)  #define tt_(o)		((o)->u.i.tt__) -#elif !defined(TValuefields) -#error option 'LUA_NANTRICK' needs declaration for 'TValuefields' +#endif				/* } */ -#endif +#endif			/* } */  /* correspondence with standard representation */ @@ -348,21 +364,18 @@ typedef struct lua_TValue TValue;  */  #undef checktag +#undef checktype  #define checktag(o,t)	(tt_(o) == tag2tt(t)) +#define checktype(o,t)	(ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS))  #undef ttisequal  #define ttisequal(o1,o2)  \  	(ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) - +#undef luai_checknum  #define luai_checknum(L,o,c)	{ if (!ttisnumber(o)) c; } - -#else - -#define luai_checknum(L,o,c)	{ /* empty */ } -  #endif  /* }====================================================== */ @@ -401,7 +414,7 @@ typedef union TString {    L_Umaxalign dummy;  /* ensures maximum alignment for strings */    struct {      CommonHeader; -    lu_byte reserved; +    lu_byte extra;  /* reserved words for short strings; "has hash" for longs */      unsigned int hash;      size_t len;  /* number of characters in string */    } tsv; @@ -501,7 +514,7 @@ typedef struct UpVal {  */  #define ClosureHeader \ -	CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist +	CommonHeader; lu_byte nupvalues; GCObject *gclist  typedef struct CClosure {    ClosureHeader; diff --git a/lua/lopcodes.c b/lua/lopcodes.c index 2e34676..ef73692 100644 --- a/lua/lopcodes.c +++ b/lua/lopcodes.c @@ -1,5 +1,6 @@  /* -** $Id: lopcodes.c,v 1.48 2011/04/19 16:22:13 roberto Exp $ +** $Id: lopcodes.c,v 1.49 2012/05/14 13:34:18 roberto Exp $ +** Opcodes for Lua virtual machine  ** See Copyright Notice in lua.h  */ diff --git a/lua/loslib.c b/lua/loslib.c index 881667d..489755b 100644 --- a/lua/loslib.c +++ b/lua/loslib.c @@ -1,5 +1,5 @@  /* -** $Id: loslib.c,v 1.38 2011/11/30 12:35:05 roberto Exp $ +** $Id: loslib.c,v 1.39 2012/05/23 15:37:09 roberto Exp $  ** Standard Operating System library  ** See Copyright Notice in lua.h  */ @@ -26,11 +26,12 @@  #if !defined(LUA_STRFTIMEOPTIONS)  #if !defined(LUA_USE_POSIX) -#define LUA_STRFTIMEOPTIONS     { "aAbBcdHIjmMpSUwWxXyYz%", "" } +#define LUA_STRFTIMEOPTIONS	{ "aAbBcdHIjmMpSUwWxXyYz%", "" }  #else -#define LUA_STRFTIMEOPTIONS     { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ -                                "E", "cCxXyY",  \ -                                "O", "deHImMSuUVwWy" } +#define LUA_STRFTIMEOPTIONS \ +	{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ +	  "", "E", "cCxXyY",  \ +	  "O", "deHImMSuUVwWy" }  #endif  #endif @@ -43,7 +44,7 @@  */  #if defined(LUA_USE_MKSTEMP)  #include <unistd.h> -#define LUA_TMPNAMBUFSIZE       32 +#define LUA_TMPNAMBUFSIZE	32  #define lua_tmpnam(b,e) { \          strcpy(b, "/tmp/lua_XXXXXX"); \          e = mkstemp(b); \ @@ -52,8 +53,8 @@  #elif !defined(lua_tmpnam) -#define LUA_TMPNAMBUFSIZE       L_tmpnam -#define lua_tmpnam(b,e)         { e = (tmpnam(b) == NULL); } +#define LUA_TMPNAMBUFSIZE	L_tmpnam +#define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); }  #endif diff --git a/lua/lparser.c b/lua/lparser.c index 4d68936..b3eb3ca 100644 --- a/lua/lparser.c +++ b/lua/lparser.c @@ -1,5 +1,5 @@  /* -** $Id: lparser.c,v 2.124 2011/12/02 13:23:56 roberto Exp $ +** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 roberto Exp $  ** Lua Parser  ** See Copyright Notice in lua.h  */ @@ -222,7 +222,7 @@ static int searchupvalue (FuncState *fs, TString *name) {    int i;    Upvaldesc *up = fs->f->upvalues;    for (i = 0; i < fs->nups; i++) { -    if (eqstr(up[i].name, name)) return i; +    if (luaS_eqstr(up[i].name, name)) return i;    }    return -1;  /* not found */  } @@ -246,7 +246,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {  static int searchvar (FuncState *fs, TString *n) {    int i;    for (i=fs->nactvar-1; i >= 0; i--) { -    if (eqstr(n, getlocvar(fs, i)->varname)) +    if (luaS_eqstr(n, getlocvar(fs, i)->varname))        return i;    }    return -1;  /* not found */ @@ -342,7 +342,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {    FuncState *fs = ls->fs;    Labellist *gl = &ls->dyd->gt;    Labeldesc *gt = &gl->arr[g]; -  lua_assert(eqstr(gt->name, label->name)); +  lua_assert(luaS_eqstr(gt->name, label->name));    if (gt->nactvar < label->nactvar) {      TString *vname = getlocvar(fs, gt->nactvar)->varname;      const char *msg = luaO_pushfstring(ls->L, @@ -369,7 +369,7 @@ static int findlabel (LexState *ls, int g) {    /* check labels in current block for a match */    for (i = bl->firstlabel; i < dyd->label.n; i++) {      Labeldesc *lb = &dyd->label.arr[i]; -    if (eqstr(lb->name, gt->name)) {  /* correct label? */ +    if (luaS_eqstr(lb->name, gt->name)) {  /* correct label? */        if (gt->nactvar > lb->nactvar &&            (bl->upval || dyd->label.n > bl->firstlabel))          luaK_patchclose(ls->fs, gt->pc, lb->nactvar); @@ -403,7 +403,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {    Labellist *gl = &ls->dyd->gt;    int i = ls->fs->bl->firstgoto;    while (i < gl->n) { -    if (eqstr(gl->arr[i].name, lb->name)) +    if (luaS_eqstr(gl->arr[i].name, lb->name))        closegoto(ls, i, lb);      else        i++; @@ -461,7 +461,7 @@ static void breaklabel (LexState *ls) {  ** message when label name is a reserved word (which can only be 'break')  */  static l_noret undefgoto (LexState *ls, Labeldesc *gt) { -  const char *msg = (gt->name->tsv.reserved > 0) +  const char *msg = isreserved(gt->name)                      ? "<%s> at line %d not inside a loop"                      : "no visible label " LUA_QS " for <goto> at line %d";    msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); @@ -493,21 +493,30 @@ static void leaveblock (FuncState *fs) {  /* -** adds prototype being created into its parent list of prototypes -** and codes instruction to create new closure +** adds a new prototype into list of prototypes  */ -static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { -  FuncState *fs = ls->fs->prev; -  Proto *f = fs->f;  /* prototype of function creating new closure */ +static Proto *addprototype (LexState *ls) { +  Proto *clp; +  lua_State *L = ls->L; +  FuncState *fs = ls->fs; +  Proto *f = fs->f;  /* prototype of current function */    if (fs->np >= f->sizep) {      int oldsize = f->sizep; -    luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, -                    MAXARG_Bx, "functions"); +    luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");      while (oldsize < f->sizep) f->p[oldsize++] = NULL;    } -  f->p[fs->np++] = clp; -  luaC_objbarrier(ls->L, f, clp); -  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); +  f->p[fs->np++] = clp = luaF_newproto(L); +  luaC_objbarrier(L, f, clp); +  return clp; +} + + +/* +** codes instruction to create new closure in parent function +*/ +static void codeclosure (LexState *ls, expdesc *v) { +  FuncState *fs = ls->fs->prev; +  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));    luaK_exp2nextreg(fs, v);  /* fix it at stack top (for GC) */  } @@ -529,13 +538,9 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {    fs->nactvar = 0;    fs->firstlocal = ls->dyd->actvar.n;    fs->bl = NULL; -  f = luaF_newproto(L); -  fs->f = f; +  f = fs->f;    f->source = ls->source;    f->maxstacksize = 2;  /* registers 0/1 are always valid */ -  /* anchor prototype (to avoid being collected) */ -  setptvalue2s(L, L->top, f); -  incr_top(L);    fs->h = luaH_new(L);    /* anchor table of constants (to avoid being collected) */    sethvalue2s(L, L->top, fs->h); @@ -568,20 +573,6 @@ static void close_func (LexState *ls) {    anchor_token(ls);    L->top--;  /* pop table of constants */    luaC_checkGC(L); -  L->top--;  /* pop prototype (after possible collection) */ -} - - -/* -** opens the main function, which is a regular vararg function with an -** upvalue named LUA_ENV -*/ -static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) { -  expdesc v; -  open_func(ls, fs, bl); -  fs->f->is_vararg = 1;  /* main function is always vararg */ -  init_exp(&v, VLOCAL, 0); -  newupvalue(fs, ls->envn, &v);  /* create environment upvalue */  } @@ -795,8 +786,9 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {    /* body ->  `(' parlist `)' block END */    FuncState new_fs;    BlockCnt bl; -  open_func(ls, &new_fs, &bl); +  new_fs.f = addprototype(ls);    new_fs.f->linedefined = line; +  open_func(ls, &new_fs, &bl);    checknext(ls, '(');    if (ismethod) {      new_localvarliteral(ls, "self");  /* create 'self' parameter */ @@ -807,7 +799,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {    statlist(ls);    new_fs.f->lastlinedefined = ls->linenumber;    check_match(ls, TK_END, TK_FUNCTION, line); -  codeclosure(ls, new_fs.f, e); +  codeclosure(ls, e);    close_func(ls);  } @@ -879,8 +871,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {  */ -static void prefixexp (LexState *ls, expdesc *v) { -  /* prefixexp -> NAME | '(' expr ')' */ +static void primaryexp (LexState *ls, expdesc *v) { +  /* primaryexp -> NAME | '(' expr ')' */    switch (ls->t.token) {      case '(': {        int line = ls->linenumber; @@ -901,12 +893,12 @@ static void prefixexp (LexState *ls, expdesc *v) {  } -static void primaryexp (LexState *ls, expdesc *v) { -  /* primaryexp -> -        prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ +static void suffixedexp (LexState *ls, expdesc *v) { +  /* suffixedexp -> +       primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */    FuncState *fs = ls->fs;    int line = ls->linenumber; -  prefixexp(ls, v); +  primaryexp(ls, v);    for (;;) {      switch (ls->t.token) {        case '.': {  /* fieldsel */ @@ -941,7 +933,7 @@ static void primaryexp (LexState *ls, expdesc *v) {  static void simpleexp (LexState *ls, expdesc *v) {    /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | -                  constructor | FUNCTION body | primaryexp */ +                  constructor | FUNCTION body | suffixedexp */    switch (ls->t.token) {      case TK_NUMBER: {        init_exp(v, VKNUM, 0); @@ -981,7 +973,7 @@ static void simpleexp (LexState *ls, expdesc *v) {        return;      }      default: { -      primaryexp(ls, v); +      suffixedexp(ls, v);        return;      }    } @@ -1141,10 +1133,10 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {  static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {    expdesc e;    check_condition(ls, vkisvar(lh->v.k), "syntax error"); -  if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */ +  if (testnext(ls, ',')) {  /* assignment -> ',' suffixedexp assignment */      struct LHS_assign nv;      nv.prev = lh; -    primaryexp(ls, &nv.v); +    suffixedexp(ls, &nv.v);      if (nv.v.k != VINDEXED)        check_conflict(ls, lh, &nv.v);      checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, @@ -1200,7 +1192,7 @@ static void gotostat (LexState *ls, int pc) {  static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {    int i;    for (i = fs->bl->firstlabel; i < ll->n; i++) { -    if (eqstr(label, ll->arr[i].name)) { +    if (luaS_eqstr(label, ll->arr[i].name)) {        const char *msg = luaO_pushfstring(fs->ls->L,                            "label " LUA_QS " already defined on line %d",                            getstr(label), ll->arr[i].line); @@ -1210,6 +1202,13 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {  } +/* skip no-op statements */ +static void skipnoopstat (LexState *ls) { +  while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) +    statement(ls); +} + +  static void labelstat (LexState *ls, TString *label, int line) {    /* label -> '::' NAME '::' */    FuncState *fs = ls->fs; @@ -1219,9 +1218,7 @@ static void labelstat (LexState *ls, TString *label, int line) {    checknext(ls, TK_DBCOLON);  /* skip double colon */    /* create new entry for this label */    l = newlabelentry(ls, ll, label, line, fs->pc); -  /* skip other no-op statements */ -  while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) -    statement(ls); +  skipnoopstat(ls);  /* skip other no-op statements */    if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */      /* assume that locals are already out of scope */      ll->arr[l].nactvar = fs->bl->nactvar; @@ -1384,6 +1381,7 @@ static void test_then_block (LexState *ls, int *escapelist) {      luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */      enterblock(fs, &bl, 0);  /* must enter block before 'goto' */      gotostat(ls, v.t);  /* handle goto/break */ +    skipnoopstat(ls);  /* skip other no-op statements */      if (block_follow(ls, 0)) {  /* 'goto' is the entire block? */        leaveblock(fs);        return;  /* and that is it */ @@ -1480,13 +1478,15 @@ static void exprstat (LexState *ls) {    /* stat -> func | assignment */    FuncState *fs = ls->fs;    struct LHS_assign v; -  primaryexp(ls, &v.v); -  if (v.v.k == VCALL)  /* stat -> func */ -    SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */ -  else {  /* stat -> assignment */ +  suffixedexp(ls, &v.v); +  if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */      v.prev = NULL;      assignment(ls, &v, 1);    } +  else {  /* stat -> func */ +    check_condition(ls, v.v.k == VCALL, "syntax error"); +    SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */ +  }  } @@ -1594,27 +1594,42 @@ static void statement (LexState *ls) {  /* }====================================================================== */ -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, -                    Dyndata *dyd, const char *name, int firstchar) { +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { +  BlockCnt bl; +  expdesc v; +  open_func(ls, fs, &bl); +  fs->f->is_vararg = 1;  /* main function is always vararg */ +  init_exp(&v, VLOCAL, 0);  /* create and... */ +  newupvalue(fs, ls->envn, &v);  /* ...set environment upvalue */ +  luaX_next(ls);  /* read first token */ +  statlist(ls);  /* parse main body */ +  check(ls, TK_EOS); +  close_func(ls); +} + + +Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, +                      Dyndata *dyd, const char *name, int firstchar) {    LexState lexstate;    FuncState funcstate; -  BlockCnt bl; -  TString *tname = luaS_new(L, name); -  setsvalue2s(L, L->top, tname);  /* push name to protect it */ +  Closure *cl = luaF_newLclosure(L, 1);  /* create main closure */ +  /* anchor closure (to avoid being collected) */ +  setclLvalue(L, L->top, cl);    incr_top(L); +  funcstate.f = cl->l.p = luaF_newproto(L); +  funcstate.f->source = luaS_new(L, name);  /* create and anchor TString */    lexstate.buff = buff;    lexstate.dyd = dyd;    dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; -  luaX_setinput(L, &lexstate, z, tname, firstchar); -  open_mainfunc(&lexstate, &funcstate, &bl); -  luaX_next(&lexstate);  /* read first token */ -  statlist(&lexstate);  /* main body */ -  check(&lexstate, TK_EOS); -  close_func(&lexstate); -  L->top--;  /* pop name */ +  luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); +  mainfunc(&lexstate, &funcstate);    lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);    /* all scopes should be correctly finished */    lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); -  return funcstate.f; +  return cl;  /* it's on the stack too */  } diff --git a/lua/lparser.h b/lua/lparser.h index caabf46..301167d 100644 --- a/lua/lparser.h +++ b/lua/lparser.h @@ -1,5 +1,5 @@  /* -** $Id: lparser.h,v 1.69 2011/07/27 18:09:01 roberto Exp $ +** $Id: lparser.h,v 1.70 2012/05/08 13:53:33 roberto Exp $  ** Lua Parser  ** See Copyright Notice in lua.h  */ @@ -112,8 +112,8 @@ typedef struct FuncState {  } FuncState; -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, -                              Dyndata *dyd, const char *name, int firstchar); +LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, +                                Dyndata *dyd, const char *name, int firstchar);  #endif diff --git a/lua/lstate.c b/lua/lstate.c index 6e2801c..3c00c28 100644 --- a/lua/lstate.c +++ b/lua/lstate.c @@ -1,11 +1,12 @@  /* -** $Id: lstate.c,v 2.92 2011/10/03 17:54:25 roberto Exp $ +** $Id: lstate.c,v 2.98 2012/05/30 12:33:44 roberto Exp $  ** Global State  ** See Copyright Notice in lua.h  */  #include <stddef.h> +#include <string.h>  #define lstate_c  #define LUA_CORE @@ -38,7 +39,18 @@  #endif -#define MEMERRMSG       "not enough memory" +#define MEMERRMSG	"not enough memory" + + +/* +** a macro to help the creation of a unique random seed when a state is +** created; the seed is used to randomize hashes. +*/ +#if !defined(luai_makeseed) +#include <time.h> +#define luai_makeseed()		cast(size_t, time(NULL)) +#endif +  /* @@ -66,6 +78,28 @@ typedef struct LG {  /* +** Compute an initial seed as random as possible. In ANSI, rely on +** Address Space Layout Randomization (if present) to increase +** randomness.. +*/ +#define addbuff(b,p,e) \ +  { size_t t = cast(size_t, e); \ +    memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int makeseed (lua_State *L) { +  char buff[4 * sizeof(size_t)]; +  unsigned int h = luai_makeseed(); +  int p = 0; +  addbuff(buff, p, L);  /* heap variable */ +  addbuff(buff, p, &h);  /* local variable */ +  addbuff(buff, p, luaO_nilobject);  /* global variable */ +  addbuff(buff, p, &lua_newstate);  /* public function */ +  lua_assert(p == sizeof(buff)); +  return luaS_hash(buff, p, h); +} + + +/*  ** set GCdebt to a new value keeping the value (totalbytes + GCdebt)  ** invariant  */ @@ -242,10 +276,11 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {    g->frealloc = f;    g->ud = ud;    g->mainthread = L; +  g->seed = makeseed(L);    g->uvhead.u.l.prev = &g->uvhead;    g->uvhead.u.l.next = &g->uvhead;    g->gcrunning = 0;  /* no GC while building state */ -  g->lastmajormem = 0; +  g->GCestimate = 0;    g->strt.size = 0;    g->strt.nuse = 0;    g->strt.hash = NULL; @@ -257,6 +292,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {    g->allgc = NULL;    g->finobj = NULL;    g->tobefnz = NULL; +  g->sweepgc = g->sweepfin = NULL;    g->gray = g->grayagain = NULL;    g->weak = g->ephemeron = g->allweak = NULL;    g->totalbytes = sizeof(LG); diff --git a/lua/lstate.h b/lua/lstate.h index 4743d74..29f810b 100644 --- a/lua/lstate.h +++ b/lua/lstate.h @@ -1,5 +1,5 @@  /* -** $Id: lstate.h,v 2.74 2011/09/30 12:45:07 roberto Exp $ +** $Id: lstate.h,v 2.81 2012/06/08 15:14:04 roberto Exp $  ** Global State  ** See Copyright Notice in lua.h  */ @@ -72,6 +72,7 @@ typedef struct CallInfo {    struct CallInfo *previous, *next;  /* dynamic call link */    short nresults;  /* expected number of results from this function */    lu_byte callstatus; +  ptrdiff_t extra;    union {      struct {  /* only for Lua functions */        StkId base;  /* base for this function */ @@ -81,7 +82,6 @@ typedef struct CallInfo {        int ctx;  /* context info. in case of yields */        lua_CFunction k;  /* continuation in case of yields */        ptrdiff_t old_errfunc; -      ptrdiff_t extra;        lu_byte old_allowhook;        lu_byte status;      } c; @@ -100,6 +100,7 @@ typedef struct CallInfo {  #define CIST_YPCALL	(1<<4)	/* call is a yieldable protected call */  #define CIST_STAT	(1<<5)	/* call has an error status (pcall) */  #define CIST_TAIL	(1<<6)	/* call was tail called */ +#define CIST_HOOKYIELD	(1<<7)	/* last hook called yielded */  #define isLua(ci)	((ci)->callstatus & CIST_LUA) @@ -113,9 +114,11 @@ typedef struct global_State {    void *ud;         /* auxiliary data to `frealloc' */    lu_mem totalbytes;  /* number of bytes currently allocated - GCdebt */    l_mem GCdebt;  /* bytes allocated not yet compensated by the collector */ -  lu_mem lastmajormem;  /* memory in use after last major collection */ +  lu_mem GCmemtrav;  /* memory traversed by the GC */ +  lu_mem GCestimate;  /* an estimate of the non-garbage memory in use */    stringtable strt;  /* hash table for strings */    TValue l_registry; +  unsigned int seed;  /* randomized seed for hashes */    lu_byte currentwhite;    lu_byte gcstate;  /* state of garbage collector */    lu_byte gckind;  /* kind of GC running */ @@ -123,7 +126,8 @@ typedef struct global_State {    int sweepstrgc;  /* position of sweep in `strt' */    GCObject *allgc;  /* list of all collectable objects */    GCObject *finobj;  /* list of collectable objects with finalizers */ -  GCObject **sweepgc;  /* current position of sweep */ +  GCObject **sweepgc;  /* current position of sweep in list 'allgc' */ +  GCObject **sweepfin;  /* current position of sweep in list 'finobj' */    GCObject *gray;  /* list of gray objects */    GCObject *grayagain;  /* list of objects to be traversed atomically */    GCObject *weak;  /* list of tables with weak values */ @@ -193,11 +197,15 @@ union GCObject {  #define gch(o)		(&(o)->gch)  /* macros to convert a GCObject into a specific value */ -#define rawgco2ts(o)	check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define rawgco2ts(o)  \ +	check_exp(novariant((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 gco2lcl(o)	check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l)) +#define gco2ccl(o)	check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c)) +#define gco2cl(o)  \ +	check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))  #define gco2t(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)) diff --git a/lua/lstring.c b/lua/lstring.c index adec415..8b959f1 100644 --- a/lua/lstring.c +++ b/lua/lstring.c @@ -1,5 +1,5 @@  /* -** $Id: lstring.c,v 2.19 2011/05/03 16:01:57 roberto Exp $ +** $Id: lstring.c,v 2.24 2012/05/11 14:14:42 roberto Exp $  ** String table (keeps all strings handled by Lua)  ** See Copyright Notice in lua.h  */ @@ -18,7 +18,49 @@  #include "lstring.h" +/* +** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to +** compute its hash +*/ +#if !defined(LUAI_HASHLIMIT) +#define LUAI_HASHLIMIT		5 +#endif + + +/* +** equality for long strings +*/ +int luaS_eqlngstr (TString *a, TString *b) { +  size_t len = a->tsv.len; +  lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); +  return (a == b) ||  /* same instance or... */ +    ((len == b->tsv.len) &&  /* equal length and ... */ +     (memcmp(getstr(a), getstr(b), len) == 0));  /* equal contents */ +} + + +/* +** equality for strings +*/ +int luaS_eqstr (TString *a, TString *b) { +  return (a->tsv.tt == b->tsv.tt) && +         (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { +  unsigned int h = seed ^ l; +  size_t l1; +  size_t step = (l >> LUAI_HASHLIMIT) + 1; +  for (l1 = l; l1 >= step; l1 -= step) +    h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); +  return h; +} + +/* +** resizes the string table +*/  void luaS_resize (lua_State *L, int newsize) {    int i;    stringtable *tb = &G(L)->strt; @@ -50,37 +92,49 @@ void luaS_resize (lua_State *L, int newsize) {  } -static TString *newlstr (lua_State *L, const char *str, size_t l, -                                       unsigned int h) { -  size_t totalsize;  /* total size of TString object */ -  GCObject **list;  /* (pointer to) list where it will be inserted */ +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, const char *str, size_t l, +                              int tag, unsigned int h, GCObject **list) {    TString *ts; -  stringtable *tb = &G(L)->strt; -  if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) -    luaM_toobig(L); -  if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) -    luaS_resize(L, tb->size*2);  /* too crowded */ +  size_t totalsize;  /* total size of TString object */    totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); -  list = &tb->hash[lmod(h, tb->size)]; -  ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts; +  ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts;    ts->tsv.len = l;    ts->tsv.hash = h; -  ts->tsv.reserved = 0; +  ts->tsv.extra = 0;    memcpy(ts+1, str, l*sizeof(char));    ((char *)(ts+1))[l] = '\0';  /* ending 0 */ -  tb->nuse++;    return ts;  } -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { +/* +** creates a new short string, inserting it into string table +*/ +static TString *newshrstr (lua_State *L, const char *str, size_t l, +                                       unsigned int h) { +  GCObject **list;  /* (pointer to) list where it will be inserted */ +  stringtable *tb = &G(L)->strt; +  TString *s; +  if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) +    luaS_resize(L, tb->size*2);  /* too crowded */ +  list = &tb->hash[lmod(h, tb->size)]; +  s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); +  tb->nuse++; +  return s; +} + + +/* +** checks whether short string exists and reuses it or creates a new one +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) {    GCObject *o; -  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 */ -    h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); -  for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; +  global_State *g = G(L); +  unsigned int h = luaS_hash(str, l, g->seed); +  for (o = g->strt.hash[lmod(h, g->strt.size)];         o != NULL;         o = gch(o)->next) {      TString *ts = rawgco2ts(o); @@ -92,10 +146,27 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {        return ts;      }    } -  return newlstr(L, str, l, h);  /* not found; create a new string */ +  return newshrstr(L, str, l, h);  /* not found; create a new string */ +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { +  if (l <= LUAI_MAXSHORTLEN)  /* short string? */ +    return internshrstr(L, str, l); +  else { +    if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) +      luaM_toobig(L); +    return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); +  }  } +/* +** new zero-terminated string +*/  TString *luaS_new (lua_State *L, const char *str) {    return luaS_newlstr(L, str, strlen(str));  } diff --git a/lua/lstring.h b/lua/lstring.h index d708a1b..d312ff3 100644 --- a/lua/lstring.h +++ b/lua/lstring.h @@ -1,5 +1,5 @@  /* -** $Id: lstring.h,v 1.46 2010/04/05 16:26:37 roberto Exp $ +** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp $  ** String table (keep all strings handled by Lua)  ** See Copyright Notice in lua.h  */ @@ -23,11 +23,20 @@  /* -** as all string are internalized, string equality becomes -** pointer equality +** test whether a string is a reserved word  */ -#define eqstr(a,b)	((a) == (b)) +#define isreserved(s)	((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b)	check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC int luaS_eqstr (TString *a, TString *b);  LUAI_FUNC void luaS_resize (lua_State *L, int newsize);  LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);  LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); diff --git a/lua/lstrlib.c b/lua/lstrlib.c index f5d61fd..e13098b 100644 --- a/lua/lstrlib.c +++ b/lua/lstrlib.c @@ -1,5 +1,5 @@  /* -** $Id: lstrlib.c,v 1.173 2011/11/30 18:24:56 roberto Exp $ +** $Id: lstrlib.c,v 1.176 2012/05/23 15:37:09 roberto Exp $  ** Standard library for string operations and pattern-matching  ** See Copyright Notice in lua.h  */ @@ -30,7 +30,7 @@  /* macro to `unsign' a character */ -#define uchar(c)        ((unsigned char)(c)) +#define uchar(c)	((unsigned char)(c)) @@ -119,7 +119,9 @@ static int str_rep (lua_State *L) {      char *p = luaL_buffinitsize(L, &b, totallen);      while (n-- > 1) {  /* first n-1 copies (followed by separator) */        memcpy(p, s, l * sizeof(char)); p += l; -      memcpy(p, sep, lsep * sizeof(char)); p += lsep; +      if (lsep > 0) {  /* avoid empty 'memcpy' (may be expensive) */ +        memcpy(p, sep, lsep * sizeof(char)); p += lsep; +      }      }      memcpy(p, s, l * sizeof(char));  /* last copy (not followed by separator) */      luaL_pushresultsize(&b, totallen); @@ -745,20 +747,17 @@ static int str_gsub (lua_State *L) {  #if !defined(LUA_INTFRMLEN)	/* { */  #if defined(LUA_USE_LONGLONG) -#define LUA_INTFRMLEN           "ll" -#define LUA_INTFRM_T            long long +#define LUA_INTFRMLEN		"ll" +#define LUA_INTFRM_T		long long  #else -#define LUA_INTFRMLEN           "l" -#define LUA_INTFRM_T            long +#define LUA_INTFRMLEN		"l" +#define LUA_INTFRM_T		long  #endif  #endif				/* } */ -#define MAX_UINTFRM	((lua_Number)(~(unsigned LUA_INTFRM_T)0)) -#define MAX_INTFRM	((lua_Number)((~(unsigned LUA_INTFRM_T)0)/2)) -#define MIN_INTFRM	(-(lua_Number)((~(unsigned LUA_INTFRM_T)0)/2) - 1)  /*  ** LUA_FLTFRMLEN is the length modifier for float conversions in @@ -767,8 +766,8 @@ static int str_gsub (lua_State *L) {  */  #if !defined(LUA_FLTFRMLEN) -#define LUA_FLTFRMLEN           "" -#define LUA_FLTFRM_T            double +#define LUA_FLTFRMLEN		"" +#define LUA_FLTFRM_T		double  #endif @@ -870,18 +869,22 @@ static int str_format (lua_State *L) {          }          case 'd':  case 'i': {            lua_Number n = luaL_checknumber(L, arg); -          luaL_argcheck(L, (MIN_INTFRM - 1) < n && n < (MAX_INTFRM + 1), arg, +          LUA_INTFRM_T ni = (LUA_INTFRM_T)n; +          lua_Number diff = n - (lua_Number)ni; +          luaL_argcheck(L, -1 < diff && diff < 1, arg,                          "not a number in proper range");            addlenmod(form, LUA_INTFRMLEN); -          nb = sprintf(buff, form, (LUA_INTFRM_T)n); +          nb = sprintf(buff, form, ni);            break;          }          case 'o':  case 'u':  case 'x':  case 'X': {            lua_Number n = luaL_checknumber(L, arg); -          luaL_argcheck(L, 0 <= n && n < (MAX_UINTFRM + 1), arg, +          unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; +          lua_Number diff = n - (lua_Number)ni; +          luaL_argcheck(L, -1 < diff && diff < 1, arg,                          "not a non-negative number in proper range");            addlenmod(form, LUA_INTFRMLEN); -          nb = sprintf(buff, form, (unsigned LUA_INTFRM_T)n); +          nb = sprintf(buff, form, ni);            break;          }          case 'e':  case 'E': case 'f': diff --git a/lua/ltable.c b/lua/ltable.c index 9581add..ffa5ecb 100644 --- a/lua/ltable.c +++ b/lua/ltable.c @@ -1,5 +1,5 @@  /* -** $Id: ltable.c,v 2.67 2011/11/30 12:41:45 roberto Exp $ +** $Id: ltable.c,v 2.71 2012/05/23 15:37:09 roberto Exp $  ** Lua tables (hash)  ** See Copyright Notice in lua.h  */ @@ -48,10 +48,10 @@  #define MAXASIZE	(1 << MAXBITS) -#define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t)))) +#define hashpow2(t,n)		(gnode(t, lmod((n), sizenode(t)))) -#define hashstr(t,str)  hashpow2(t, (str)->tsv.hash) -#define hashboolean(t,p)        hashpow2(t, p) +#define hashstr(t,str)		hashpow2(t, (str)->tsv.hash) +#define hashboolean(t,p)	hashpow2(t, p)  /* @@ -98,7 +98,15 @@ static Node *mainposition (const Table *t, const TValue *key) {    switch (ttype(key)) {      case LUA_TNUMBER:        return hashnum(t, nvalue(key)); -    case LUA_TSTRING: +    case LUA_TLNGSTR: { +      TString *s = rawtsvalue(key); +      if (s->tsv.extra == 0) {  /* no hash? */ +        s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); +        s->tsv.extra = 1;  /* now it has its hash */ +      } +      return hashstr(t, rawtsvalue(key)); +    } +    case LUA_TSHRSTR:        return hashstr(t, rawtsvalue(key));      case LUA_TBOOLEAN:        return hashboolean(t, bvalue(key)); @@ -453,12 +461,13 @@ const TValue *luaH_getint (Table *t, int key) {  /* -** search function for strings +** search function for short strings  */  const TValue *luaH_getstr (Table *t, TString *key) {    Node *n = hashstr(t, key); +  lua_assert(key->tsv.tt == LUA_TSHRSTR);    do {  /* check whether `key' is somewhere in the chain */ -    if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key)) +    if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key))        return gval(n);  /* that's it */      else n = gnext(n);    } while (n); @@ -470,9 +479,9 @@ const TValue *luaH_getstr (Table *t, TString *key) {  ** main search function  */  const TValue *luaH_get (Table *t, const TValue *key) { -  switch (ttypenv(key)) { +  switch (ttype(key)) {      case LUA_TNIL: return luaO_nilobject; -    case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); +    case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key));      case LUA_TNUMBER: {        int k;        lua_Number n = nvalue(key); @@ -1,5 +1,5 @@  /* -** $Id: lua.c,v 1.203 2011/12/12 16:34:03 roberto Exp $ +** $Id: lua.c,v 1.205 2012/05/23 15:37:09 roberto Exp $  ** Lua stand-alone interpreter  ** See Copyright Notice in lua.h  */ @@ -45,13 +45,13 @@  */  #if defined(LUA_USE_ISATTY)  #include <unistd.h> -#define lua_stdin_is_tty()      isatty(0) +#define lua_stdin_is_tty()	isatty(0)  #elif defined(LUA_WIN)  #include <io.h>  #include <stdio.h> -#define lua_stdin_is_tty()      _isatty(_fileno(stdin)) +#define lua_stdin_is_tty()	_isatty(_fileno(stdin))  #else -#define lua_stdin_is_tty()      1  /* assume stdin is a tty */ +#define lua_stdin_is_tty()	1  /* assume stdin is a tty */  #endif @@ -66,19 +66,19 @@  #include <stdio.h>  #include <readline/readline.h>  #include <readline/history.h> -#define lua_readline(L,b,p)     ((void)L, ((b)=readline(p)) != NULL) +#define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)  #define lua_saveline(L,idx) \          if (lua_rawlen(L,idx) > 0)  /* non-empty line? */ \            add_history(lua_tostring(L, idx));  /* add it to history */ -#define lua_freeline(L,b)       ((void)L, free(b)) +#define lua_freeline(L,b)	((void)L, free(b))  #elif !defined(lua_readline) -#define lua_readline(L,b,p)     \ +#define lua_readline(L,b,p) \          ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \          fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */ -#define lua_saveline(L,idx)     { (void)L; (void)idx; } -#define lua_freeline(L,b)       { (void)L; (void)b; } +#define lua_saveline(L,idx)	{ (void)L; (void)idx; } +#define lua_freeline(L,b)	{ (void)L; (void)b; }  #endif @@ -223,16 +223,11 @@ static int dostring (lua_State *L, const char *s, const char *name) {  static int dolibrary (lua_State *L, const char *name) {    int status; -  lua_pushglobaltable(L); -  lua_getfield(L, -1, "require"); +  lua_getglobal(L, "require");    lua_pushstring(L, name); -  status = docall(L, 1, 1); -  if (status == LUA_OK) { -    lua_setfield(L, -2, name);  /* global[name] = require return */ -    lua_pop(L, 1);  /* remove global table */ -  } -  else -    lua_remove(L, -2);  /* remove global table (below error msg.) */ +  status = docall(L, 1, 1);  /* call 'require(name)' */ +  if (status == LUA_OK) +    lua_setglobal(L, name);  /* global[name] = require return */    return report(L, status);  } @@ -1,5 +1,5 @@  /* -** $Id: lua.h,v 1.282 2011/11/29 15:55:08 roberto Exp $ +** $Id: lua.h,v 1.283 2012/04/20 13:18:26 roberto Exp $  ** Lua - A Scripting Language  ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)  ** See Copyright Notice at the end of this file @@ -19,11 +19,11 @@  #define LUA_VERSION_MAJOR	"5"  #define LUA_VERSION_MINOR	"2"  #define LUA_VERSION_NUM		502 -#define LUA_VERSION_RELEASE	"0" +#define LUA_VERSION_RELEASE	"1"  #define LUA_VERSION	"Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR  #define LUA_RELEASE	LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT	LUA_RELEASE "  Copyright (C) 1994-2011 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT	LUA_RELEASE "  Copyright (C) 1994-2012 Lua.org, PUC-Rio"  #define LUA_AUTHORS	"R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -413,7 +413,7 @@ struct lua_Debug {  /****************************************************************************** -* Copyright (C) 1994-2011 Lua.org, PUC-Rio.  All rights reserved. +* Copyright (C) 1994-2012 Lua.org, PUC-Rio.  *  * Permission is hereby granted, free of charge, to any person obtaining  * a copy of this software and associated documentation files (the diff --git a/lua/luaconf.h b/lua/luaconf.h.in index f49e8cb..b0a75e8 100644 --- a/lua/luaconf.h +++ b/lua/luaconf.h.in @@ -1,5 +1,5 @@  /* -** $Id: luaconf.h,v 1.170 2011/12/06 16:58:36 roberto Exp $ +** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $  ** Configuration file for Lua  ** See Copyright Notice in lua.h  */ @@ -11,6 +11,7 @@  #include <limits.h>  #include <stddef.h> +#define LUA_USE_LINUX  /*  ** ================================================================== @@ -99,12 +100,8 @@  #else			/* }{ */ -#define LUA_VDIR	LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/" -#ifndef LUA_ROOT -#define LUA_ROOT	"/usr/local/" -#endif -#define LUA_LDIR	LUA_ROOT "share/lua/" LUA_VDIR -#define LUA_CDIR	LUA_ROOT "lib/lua/" LUA_VDIR +#define LUA_LDIR	"@path@/" +#define LUA_CDIR	"@cpath@/"  #define LUA_PATH_DEFAULT  \  		LUA_LDIR"?.lua;"  LUA_LDIR"?/init.lua;" \  		LUA_CDIR"?.lua;"  LUA_CDIR"?/init.lua;" "./?.lua" @@ -225,6 +222,13 @@  	(fprintf(stderr, (s), (p)), fflush(stderr)) +/* +@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is, +** strings that are internalized. (Cannot be smaller than reserved words +** or tags for metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#define LUAI_MAXSHORTLEN        40 @@ -455,66 +459,76 @@  #define LUA_UNSIGNED	unsigned LUA_INT32 -#if defined(LUA_CORE)		/* { */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI)	/* { */ +/* +** Some tricks with doubles +*/ + +#if defined(LUA_CORE) && \ +    defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI)	/* { */ +/* +** The next definitions activate some tricks to speed up the +** conversion from doubles to integer types, mainly to LUA_UNSIGNED. +** +@@ MS_ASMTRICK uses Microsoft assembler to avoid clashes with a +** DirectX idiosyncrasy. +** +@@ LUA_IEEE754TRICK uses a trick that should work on any machine +** using IEEE754 with a 32-bit integer type. +** +@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be +** defined when LUA_INTEGER is a 32-bit integer. +** +@@ LUA_IEEEENDIAN is the endianness of doubles in your machine +** (0 for little endian, 1 for big endian); if not defined, Lua will +** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK). +** +@@ LUA_NANTRICK controls the use of a trick to pack all types into +** a single double value, using NaN values to represent non-number +** values. The trick only works on 32-bit machines (ints and pointers +** are 32-bit values) with numbers represented as IEEE 754-2008 doubles +** with conventional endianess (12345678 or 87654321), in CPUs that do +** not produce signaling NaN values (all NaNs are quiet). +*/ -/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes -   with a DirectX idiosyncrasy */ +/* Microsoft compiler on a Pentium (32 bit) ? */  #if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86)	/* { */  #define MS_ASMTRICK +#define LUA_IEEEENDIAN		0 +#define LUA_NANTRICK -#else				/* }{ */ -/* the next definition uses a trick that should work on any machine -   using IEEE754 with a 32-bit integer type */ -#define LUA_IEEE754TRICK +/* pentium 32 bits? */ +#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ -/* -@@ LUA_IEEEENDIAN is the endianness of doubles in your machine -** (0 for little endian, 1 for big endian); if not defined, Lua will -** check it dynamically. -*/ -/* check for known architectures */ -#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ -    defined (__x86_64) -#define LUA_IEEEENDIAN	0 -#elif defined(__POWERPC__) || defined(__ppc__) -#define LUA_IEEEENDIAN	1 -#endif +#define LUA_IEEE754TRICK +#define LUA_IEEELL +#define LUA_IEEEENDIAN		0 +#define LUA_NANTRICK -#endif				/* } */ +/* pentium 64 bits? */ +#elif defined(__x86_64)						/* }{ */ -#endif			/* } */ - -#endif			/* } */ - -/* }================================================================== */ +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN		0 +#elif defined(__POWERPC__) || defined(__ppc__)			/* }{ */ -/* -@@ LUA_NANTRICK_LE/LUA_NANTRICK_BE controls the use of a trick to -** pack all types into a single double value, using NaN values to -** represent non-number values. The trick only works on 32-bit machines -** (ints and pointers are 32-bit values) with numbers represented as -** IEEE 754-2008 doubles with conventional endianess (12345678 or -** 87654321), in CPUs that do not produce signaling NaN values (all NaNs -** are quiet). -*/ -#if defined(LUA_CORE) && \ -    defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI)	/* { */ +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN		1 -/* little-endian architectures that satisfy those conditions */ -#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ -    defined(_M_IX86) +#else								/* }{ */ -#define LUA_NANTRICK_LE +/* assume IEEE754 and a 32-bit integer type */ +#define LUA_IEEE754TRICK -#endif +#endif								/* } */  #endif							/* } */ +/* }================================================================== */ + diff --git a/lua/lundump.c b/lua/lundump.c index 80c7aa3..54de011 100644 --- a/lua/lundump.c +++ b/lua/lundump.c @@ -1,5 +1,5 @@  /* -** $Id: lundump.c,v 1.71 2011/12/07 10:39:12 lhf Exp $ +** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp $  ** load precompiled Lua chunks  ** See Copyright Notice in lua.h  */ @@ -27,7 +27,7 @@ typedef struct {   const char* name;  } LoadState; -static void error(LoadState* S, const char* why) +static l_noret error(LoadState* S, const char* why)  {   luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why);   luaD_throw(S->L,LUA_ERRSYNTAX); @@ -39,7 +39,7 @@ static void error(LoadState* S, const char* why)  #define LoadVector(S,b,n,size)	LoadMem(S,b,n,size)  #if !defined(luai_verifycode) -#define luai_verifycode(L,b,f)	(f) +#define luai_verifycode(L,b,f)	/* empty */  #endif  static void LoadBlock(LoadState* S, void* b, size_t size) @@ -91,7 +91,7 @@ static void LoadCode(LoadState* S, Proto* f)   LoadVector(S,f->code,n,sizeof(Instruction));  } -static Proto* LoadFunction(LoadState* S); +static void LoadFunction(LoadState* S, Proto* f);  static void LoadConstants(LoadState* S, Proto* f)  { @@ -118,13 +118,18 @@ static void LoadConstants(LoadState* S, Proto* f)     case LUA_TSTRING:  	setsvalue2n(S->L,o,LoadString(S));  	break; +    default: lua_assert(0);    }   }   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); + for (i=0; i<n; i++) + { +  f->p[i]=luaF_newproto(S->L); +  LoadFunction(S,f->p[i]); + }  }  static void LoadUpvalues(LoadState* S, Proto* f) @@ -163,10 +168,8 @@ static void LoadDebug(LoadState* S, Proto* f)   for (i=0; i<n; i++) f->upvalues[i].name=LoadString(S);  } -static Proto* LoadFunction(LoadState* S) +static void LoadFunction(LoadState* S, Proto* f)  { - Proto* f=luaF_newproto(S->L); - setptvalue2s(S->L,S->L->top,f); incr_top(S->L);   f->linedefined=LoadInt(S);   f->lastlinedefined=LoadInt(S);   f->numparams=LoadByte(S); @@ -176,8 +179,6 @@ static Proto* LoadFunction(LoadState* S)   LoadConstants(S,f);   LoadUpvalues(S,f);   LoadDebug(S,f); - S->L->top--; - return f;  }  /* the code below must be consistent with the code in luaU_header */ @@ -202,9 +203,10 @@ static void LoadHeader(LoadState* S)  /*  ** load precompiled chunk  */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) +Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)  {   LoadState S; + Closure* cl;   if (*name=='@' || *name=='=')    S.name=name+1;   else if (*name==LUA_SIGNATURE[0]) @@ -215,7 +217,19 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)   S.Z=Z;   S.b=buff;   LoadHeader(&S); - return luai_verifycode(L,buff,LoadFunction(&S)); + cl=luaF_newLclosure(L,1); + setclLvalue(L,L->top,cl); incr_top(L); + cl->l.p=luaF_newproto(L); + LoadFunction(&S,cl->l.p); + if (cl->l.p->sizeupvalues != 1) + { +  Proto* p=cl->l.p; +  cl=luaF_newLclosure(L,cl->l.p->sizeupvalues); +  cl->l.p=p; +  setclLvalue(L,L->top-1,cl); + } + luai_verifycode(L,buff,cl->l.p); + return cl;  }  #define MYINT(s)	(s[0]-'0') diff --git a/lua/lundump.h b/lua/lundump.h index b63993f..2b8acce 100644 --- a/lua/lundump.h +++ b/lua/lundump.h @@ -1,5 +1,5 @@  /* -** $Id: lundump.h,v 1.44 2011/05/06 13:35:17 lhf Exp $ +** $Id: lundump.h,v 1.39 2012/05/08 13:53:33 roberto Exp $  ** load precompiled Lua chunks  ** See Copyright Notice in lua.h  */ @@ -11,7 +11,7 @@  #include "lzio.h"  /* load one chunk; from lundump.c */ -LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); +LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);  /* make header; from lundump.c */  LUAI_FUNC void luaU_header (lu_byte* h); @@ -1,5 +1,5 @@  /* -** $Id: lvm.c,v 2.147 2011/12/07 14:43:55 roberto Exp $ +** $Id: lvm.c,v 2.152 2012/06/08 15:14:04 roberto Exp $  ** Lua virtual machine  ** See Copyright Notice in lua.h  */ @@ -60,10 +60,15 @@ int luaV_tostring (lua_State *L, StkId obj) {  static void traceexec (lua_State *L) {    CallInfo *ci = L->ci;    lu_byte mask = L->hookmask; -  if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { -    resethookcount(L); -    luaD_hook(L, LUA_HOOKCOUNT, -1); +  int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); +  if (counthook) +    resethookcount(L);  /* reset count */ +  if (ci->callstatus & CIST_HOOKYIELD) {  /* called hook last time? */ +    ci->callstatus &= ~CIST_HOOKYIELD;  /* erase mark */ +    return;  /* do not call hook again (VM yielded, so it did not move) */    } +  if (counthook) +    luaD_hook(L, LUA_HOOKCOUNT, -1);  /* call count hook */    if (mask & LUA_MASKLINE) {      Proto *p = ci_func(ci)->p;      int npc = pcRel(ci->u.l.savedpc, p); @@ -71,11 +76,15 @@ static void traceexec (lua_State *L) {      if (npc == 0 ||  /* call linehook when enter a new function, */          ci->u.l.savedpc <= L->oldpc ||  /* when jump back (loop), or when */          newline != getfuncline(p, pcRel(L->oldpc, p)))  /* enter a new line */ -      luaD_hook(L, LUA_HOOKLINE, newline); +      luaD_hook(L, LUA_HOOKLINE, newline);  /* call line hook */    }    L->oldpc = ci->u.l.savedpc;    if (L->status == LUA_YIELD) {  /* did hook yield? */ +    if (counthook) +      L->hookcount = 1;  /* undo decrement to zero */      ci->u.l.savedpc--;  /* undo increment (resume will increment it again) */ +    ci->callstatus |= CIST_HOOKYIELD;  /* mark that it yieled */ +    ci->func = L->top - 1;  /* protect stack below results */      luaD_throw(L, LUA_YIELD);    }  } @@ -258,7 +267,8 @@ int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) {      case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */      case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);      case LUA_TLCF: return fvalue(t1) == fvalue(t2); -    case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2)); +    case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); +    case LUA_TLNGSTR: return luaS_eqlngstr(rawtsvalue(t1), rawtsvalue(t2));      case LUA_TUSERDATA: {        if (uvalue(t1) == uvalue(t2)) return 1;        else if (L == NULL) return 0; @@ -293,7 +303,7 @@ void luaV_concat (lua_State *L, int total) {      else if (tsvalue(top-1)->len == 0)  /* second operand is empty? */        (void)tostring(L, top - 2);  /* result is first operand */      else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { -      setsvalue2s(L, top-2, rawtsvalue(top-1));  /* result is second op. */ +      setobjs2s(L, top - 2, top - 1);  /* result is second op. */      }      else {        /* at least two non-empty string values; get as many as possible */ @@ -394,7 +404,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,    int nup = p->sizeupvalues;    Upvaldesc *uv = p->upvalues;    int i; -  Closure *ncl = luaF_newLclosure(L, p); +  Closure *ncl = luaF_newLclosure(L, nup); +  ncl->l.p = p;    setclLvalue(L, ra, ncl);  /* anchor new closure in stack */    for (i = 0; i < nup; i++) {  /* fill in its upvalues */      if (uv[i].instack)  /* upvalue refers to local variable? */ @@ -500,7 +511,11 @@ void luaV_finishOp (lua_State *L) {  #define Protect(x)	{ {x;}; base = ci->u.l.base; } -#define checkGC(L,c)	Protect(luaC_condGC(L, c); luai_threadyield(L);) +#define checkGC(L,c)  \ +  Protect( luaC_condGC(L,{L->top = (c);  /* limit of live values */ \ +                          luaC_step(L); \ +                          L->top = ci->top;})  /* restore top */ \ +           luai_threadyield(L); )  #define arith_op(op,tm) { \ @@ -593,11 +608,7 @@ void luaV_execute (lua_State *L) {          sethvalue(L, ra, t);          if (b != 0 || c != 0)            luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); -        checkGC(L, -          L->top = ra + 1;  /* limit of live values */ -          luaC_step(L); -          L->top = ci->top;  /* restore top */ -        ) +        checkGC(L, ra + 1);        )        vmcase(OP_SELF,          StkId rb = RB(i); @@ -649,10 +660,7 @@ void luaV_execute (lua_State *L) {          ra = RA(i);  /* 'luav_concat' may invoke TMs and move the stack */          rb = b + base;          setobjs2s(L, ra, rb); -        checkGC(L, -          L->top = (ra >= rb ? ra + 1 : rb);  /* limit of live values */ -          luaC_step(L); -        ) +        checkGC(L, (ra >= rb ? ra + 1 : rb));          L->top = ci->top;  /* restore top */        )        vmcase(OP_JMP, @@ -830,11 +838,7 @@ void luaV_execute (lua_State *L) {            pushclosure(L, p, cl->upvals, base, ra);  /* create a new one */          else            setclLvalue(L, ra, ncl);  /* push cashed closure */ -        checkGC(L, -          L->top = ra + 1;  /* limit of live values */ -          luaC_step(L); -          L->top = ci->top;  /* restore top */ -        ) +        checkGC(L, ra + 1);        )        vmcase(OP_VARARG,          int b = GETARG_B(i) - 1; @@ -1,6 +1,6 @@  /* -** $Id: lzio.c,v 1.34 2011/07/15 12:35:32 roberto Exp $ -** a generic input stream interface +** $Id: lzio.c,v 1.35 2012/05/14 13:34:18 roberto Exp $ +** Buffered streams  ** See Copyright Notice in lua.h  */ | 
