diff options
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/lauxlib.c | 9 | ||||
-rw-r--r-- | src/ldblib.c | 21 | ||||
-rw-r--r-- | src/ldebug.c | 13 | ||||
-rw-r--r-- | src/ldump.c | 7 | ||||
-rw-r--r-- | src/lfunc.c | 15 | ||||
-rw-r--r-- | src/lfunc.h | 3 | ||||
-rw-r--r-- | src/lgc.c | 90 | ||||
-rw-r--r-- | src/lgc.h | 8 | ||||
-rw-r--r-- | src/llex.c | 27 | ||||
-rw-r--r-- | src/llimits.h | 11 | ||||
-rw-r--r-- | src/lobject.h | 35 | ||||
-rw-r--r-- | src/lparser.c | 16 | ||||
-rw-r--r-- | src/lstate.c | 37 | ||||
-rw-r--r-- | src/lstate.h | 11 | ||||
-rw-r--r-- | src/lstring.c | 103 | ||||
-rw-r--r-- | src/lstring.h | 17 | ||||
-rw-r--r-- | src/ltable.c | 23 | ||||
-rw-r--r-- | src/lua.h | 2 | ||||
-rw-r--r-- | src/lundump.c | 5 | ||||
-rw-r--r-- | src/lvm.c | 7 |
22 files changed, 325 insertions, 139 deletions
@@ -1,5 +1,5 @@ -This is Lua 5.2, released on 12 Dec 2011. +This is Lua 5.2.1, released on xx xxx 2012. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/src/Makefile b/src/Makefile index bba1693f..8c9ee677 100644 --- a/src/Makefile +++ b/src/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/src/lauxlib.c b/src/lauxlib.c index 0aa80fd9..5f4916ea 100644 --- a/src/lauxlib.c +++ b/src/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.242 2012/03/19 22:57:14 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -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; diff --git a/src/ldblib.c b/src/ldblib.c index 3c2f1595..c0226945 100644 --- a/src/ldblib.c +++ b/src/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/src/ldebug.c b/src/ldebug.c index 31b7ae40..43f8f046 100644 --- a/src/ldebug.c +++ b/src/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; } diff --git a/src/ldump.c b/src/ldump.c index 699e1dc4..ae1c780f 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.19 2011/11/23 17:48:18 lhf Exp $ +** $Id: ldump.c,v 1.20 2012/03/21 18:11:35 lhf 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/src/lfunc.c b/src/lfunc.c index 1a1a8bb8..9492283a 100644 --- a/src/lfunc.c +++ b/src/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.28 2012/01/20 22:05:50 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -21,8 +21,7 @@ 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; } @@ -30,8 +29,7 @@ Closure *luaF_newCclosure (lua_State *L, int n) { 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; + Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; c->l.p = p; c->l.nupvalues = cast_byte(n); while (n--) c->l.upvals[n] = NULL; @@ -146,13 +144,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/src/lfunc.h b/src/lfunc.h index da189231..fe8efde0 100644 --- a/src/lfunc.h +++ b/src/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.7 2012/01/20 22:05:50 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -25,7 +25,6 @@ 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.119 2012/01/25 21:05:40 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -65,7 +65,11 @@ #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))) +/* +** dirty trick: we know that 'reallymarkobject' does not use 'g' when +** object is a string +*/ +#define stringmark(s) markobject(NULL, s) #define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) @@ -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,18 +244,18 @@ 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)); white2gray(o); switch (gch(o)->tt) { - case LUA_TSTRING: { - return; /* for strings, gray is as good as black */ + case LUA_TSHRSTR: + case LUA_TLNGSTR: { + gray2black(o); + return; /* nothing else to mark */ } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; @@ -266,8 +271,13 @@ static void reallymarkobject (global_State *g, GCObject *o) { gray2black(o); /* make it black */ return; } - case LUA_TFUNCTION: { - gco2cl(o)->c.gclist = g->gray; + case LUA_TLCL: { + gco2lcl(o)->gclist = g->gray; + g->gray = o; + break; + } + case LUA_TCCL: { + gco2ccl(o)->gclist = g->gray; g->gray = o; break; } @@ -470,20 +480,20 @@ static int traverseproto (global_State *g, Proto *f) { } -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 int traverseCclosure (global_State *g, CClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return TRAVCOST + cl->nupvalues; +} + +static int traverseLclosure (global_State *g, LClosure *cl) { + int i; + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + markobject(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->upvals[i]); + return TRAVCOST + cl->nupvalues; } @@ -517,10 +527,15 @@ static int propagatemark (global_State *g) { g->gray = h->gclist; return traversetable(g, h); } - case LUA_TFUNCTION: { - Closure *cl = gco2cl(o); - g->gray = cl->c.gclist; - return traverseclosure(g, cl); + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + g->gray = cl->gclist; + return traverseLclosure(g, cl); + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + g->gray = cl->gclist; + return traverseCclosure(g, cl); } case LUA_TTHREAD: { lua_State *th = gco2th(o); @@ -640,13 +655,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; } @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.52 2011/10/03 17:54:25 roberto Exp $ +** $Id: lgc.h,v 2.53 2012/01/23 20:29:12 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -20,8 +20,10 @@ ** is that a black object can never point to a white one. Moreover, ** any gray object must be in a "gray list" (gray, grayagain, weak, ** allweak, ephemeron) so that it can be visited again before finishing -** the collection cycle. These lists have no meaning when the invariant -** is not being enforced (e.g., sweep phase). +** the collection cycle. (These rule does not apply to strings, +** which are never black but do not need to be visited again.) +** These lists have no meaning when the invariant is not being enforced +** (e.g., sweep phase). */ @@ -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/src/llimits.h b/src/llimits.h index 48dc81f7..98f8fea0 100644 --- a/src/llimits.h +++ b/src/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.96 2012/01/25 21:05:40 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -125,6 +125,15 @@ typedef LUAI_UACNUMBER l_uacNumber; /* +** maximum length for short strings, that is, strings that are +** internalized. (Cannot be smaller than reserved words or tags +** for metamethods; #"function" = 8, #"__newindex" = 10; should +** not be larger than 255, to allow future changes) +*/ +#define LUA_MAXSHORTLEN (8 * sizeof(void*)) + + +/* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ diff --git a/src/lobject.h b/src/lobject.h index 06246bfa..20dd44d4 100644 --- a/src/lobject.h +++ b/src/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.68 2012/01/25 21:05:40 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) \ @@ -348,7 +363,9 @@ 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) \ @@ -401,7 +418,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 +518,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/src/lparser.c b/src/lparser.c index 4d689365..ac4093cc 100644 --- a/src/lparser.c +++ b/src/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.125 2012/01/23 23:05:18 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); @@ -1200,7 +1200,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); diff --git a/src/lstate.c b/src/lstate.c index 6e2801c4..e3aec6a3 100644 --- a/src/lstate.c +++ b/src/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.93 2012/02/01 21:57:15 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #include <stddef.h> +#include <string.h> #define lstate_c #define LUA_CORE @@ -42,6 +43,17 @@ /* +** 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(L) cast(size_t, time(NULL)) +#endif + + + +/* ** thread state + extra space */ typedef struct LX { @@ -66,6 +78,28 @@ typedef struct LG { /* +** Compute an initial seed as random as possible. In ANSI, rely on +** Address Space Layour 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,6 +276,7 @@ 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 */ diff --git a/src/lstate.h b/src/lstate.h index 4743d741..1691ed92 100644 --- a/src/lstate.h +++ b/src/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.77 2012/02/01 21:57:15 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -116,6 +116,7 @@ typedef struct global_State { lu_mem lastmajormem; /* memory in use after last major collection */ 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 */ @@ -193,11 +194,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/src/lstring.c b/src/lstring.c index adec415e..d89ac8f2 100644 --- a/src/lstring.c +++ b/src/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.22 2012/02/01 21:57:15 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -18,7 +18,37 @@ #include "lstring.h" +/* +** 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 (len == b->tsv.len) && (memcmp(getstr(a), getstr(b), len) == 0); +} + + +/* +** 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; + for (l1 = 0; l1 < l; l1++) + h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1])); + return h; +} + +/* +** resizes the string table +*/ void luaS_resize (lua_State *L, int newsize) { int i; stringtable *tb = &G(L)->strt; @@ -50,37 +80,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 +134,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 <= LUA_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/src/lstring.h b/src/lstring.h index d708a1b0..d312ff3d 100644 --- a/src/lstring.h +++ b/src/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/src/ltable.c b/src/ltable.c index 9581add9..7f28e808 100644 --- a/src/ltable.c +++ b/src/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.70 2012/02/01 21:57:15 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -50,7 +50,7 @@ #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#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); @@ -19,7 +19,7 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" #define LUA_VERSION_NUM 502 -#define LUA_VERSION_RELEASE "0" +#define LUA_VERSION_RELEASE "0" " (work1)" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE diff --git a/src/lundump.c b/src/lundump.c index 80c7aa39..c2173daf 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.71 2011/12/07 10:39:12 lhf Exp $ +** $Id: lundump.c,v 1.72 2012/03/21 18:11:35 lhf 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); @@ -118,6 +118,7 @@ static void LoadConstants(LoadState* S, Proto* f) case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; + default: lua_assert(0); } } n=LoadInt(S); @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.147 2011/12/07 14:43:55 roberto Exp $ +** $Id: lvm.c,v 2.149 2012/01/25 21:05:40 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -258,7 +258,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 +294,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 */ |