diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-08-30 13:01:37 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-08-30 13:01:37 -0300 |
| commit | 8ef9e8460e775793f760deb28d0c3d10dda31b49 (patch) | |
| tree | 803abce8b7caba6e5f66b26e55f0bc8dcfc881a2 | |
| parent | 4f292d753c892e705b6d1796d72758cdd4d49765 (diff) | |
| download | lua-8ef9e8460e775793f760deb28d0c3d10dda31b49.tar.gz lua-8ef9e8460e775793f760deb28d0c3d10dda31b49.tar.bz2 lua-8ef9e8460e775793f760deb28d0c3d10dda31b49.zip | |
bug (GC can collect long identifier during parser) + change (using
a single constant table for all functions in a chunk)
| -rw-r--r-- | lcode.c | 20 | ||||
| -rw-r--r-- | llex.c | 15 | ||||
| -rw-r--r-- | llex.h | 3 | ||||
| -rw-r--r-- | lparser.c | 45 | ||||
| -rw-r--r-- | lparser.h | 3 | ||||
| -rw-r--r-- | ltable.h | 7 |
6 files changed, 47 insertions, 46 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lcode.c,v 2.70 2013/06/20 17:37:31 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 2.71 2013/06/25 18:57:18 roberto Exp roberto $ |
| 3 | ** Code generator for Lua | 3 | ** Code generator for Lua |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -307,17 +307,21 @@ static void freeexp (FuncState *fs, expdesc *e) { | |||
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | 309 | ||
| 310 | /* | ||
| 311 | ** Use scanner's table to cache position of constants in contant list | ||
| 312 | ** and try to reuse constants | ||
| 313 | */ | ||
| 310 | static int addk (FuncState *fs, TValue *key, TValue *v) { | 314 | static int addk (FuncState *fs, TValue *key, TValue *v) { |
| 311 | lua_State *L = fs->ls->L; | 315 | lua_State *L = fs->ls->L; |
| 312 | TValue *idx = luaH_set(L, fs->h, key); | ||
| 313 | Proto *f = fs->f; | 316 | Proto *f = fs->f; |
| 317 | TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ | ||
| 314 | int k, oldsize; | 318 | int k, oldsize; |
| 315 | if (ttisinteger(idx)) { | 319 | if (ttisinteger(idx)) { /* is there an index there? */ |
| 316 | k = ivalue(idx); | 320 | k = ivalue(idx); |
| 317 | if (luaV_rawequalobj(&f->k[k], v)) | 321 | /* correct value? (warning: must distinguish floats from integers!) */ |
| 318 | return k; | 322 | if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && |
| 319 | /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); | 323 | luaV_rawequalobj(&f->k[k], v)) |
| 320 | go through and create a new entry for this value */ | 324 | return k; /* reuse index */ |
| 321 | } | 325 | } |
| 322 | /* constant not found; create a new entry */ | 326 | /* constant not found; create a new entry */ |
| 323 | oldsize = f->sizek; | 327 | oldsize = f->sizek; |
| @@ -377,7 +381,7 @@ static int nilK (FuncState *fs) { | |||
| 377 | TValue k, v; | 381 | TValue k, v; |
| 378 | setnilvalue(&v); | 382 | setnilvalue(&v); |
| 379 | /* cannot use nil as key; instead use table itself to represent nil */ | 383 | /* cannot use nil as key; instead use table itself to represent nil */ |
| 380 | sethvalue(fs->ls->L, &k, fs->h); | 384 | sethvalue(fs->ls->L, &k, fs->ls->h); |
| 381 | return addk(fs, &k, &v); | 385 | return addk(fs, &k, &v); |
| 382 | } | 386 | } |
| 383 | 387 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: llex.c,v 2.67 2013/06/19 14:27:00 roberto Exp roberto $ | 2 | ** $Id: llex.c,v 2.68 2013/08/21 20:09:51 roberto Exp roberto $ |
| 3 | ** Lexical Analyzer | 3 | ** Lexical Analyzer |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -119,22 +119,25 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { | |||
| 119 | 119 | ||
| 120 | 120 | ||
| 121 | /* | 121 | /* |
| 122 | ** creates a new string and anchors it in function's table so that | 122 | ** creates a new string and anchors it in scanner's table so that |
| 123 | ** it will not be collected until the end of the function's compilation | 123 | ** it will not be collected until the end of the compilation |
| 124 | ** (by that time it should be anchored in function's prototype) | 124 | ** (by that time it should be anchored somewhere) |
| 125 | */ | 125 | */ |
| 126 | TString *luaX_newstring (LexState *ls, const char *str, size_t l) { | 126 | TString *luaX_newstring (LexState *ls, const char *str, size_t l) { |
| 127 | lua_State *L = ls->L; | 127 | lua_State *L = ls->L; |
| 128 | TValue *o; /* entry for `str' */ | 128 | TValue *o; /* entry for `str' */ |
| 129 | TString *ts = luaS_newlstr(L, str, l); /* create new string */ | 129 | TString *ts = luaS_newlstr(L, str, l); /* create new string */ |
| 130 | setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ | 130 | setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ |
| 131 | o = luaH_set(L, ls->fs->h, L->top - 1); | 131 | o = luaH_set(L, ls->h, L->top - 1); |
| 132 | if (ttisnil(o)) { /* not in use yet? (see 'addK') */ | 132 | if (ttisnil(o)) { /* not in use yet? */ |
| 133 | /* boolean value does not need GC barrier; | 133 | /* boolean value does not need GC barrier; |
| 134 | table has no metatable, so it does not need to invalidate cache */ | 134 | table has no metatable, so it does not need to invalidate cache */ |
| 135 | setbvalue(o, 1); /* t[string] = true */ | 135 | setbvalue(o, 1); /* t[string] = true */ |
| 136 | luaC_checkGC(L); | 136 | luaC_checkGC(L); |
| 137 | } | 137 | } |
| 138 | else { /* string already present */ | ||
| 139 | ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */ | ||
| 140 | } | ||
| 138 | L->top--; /* remove string from stack */ | 141 | L->top--; /* remove string from stack */ |
| 139 | return ts; | 142 | return ts; |
| 140 | } | 143 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: llex.h,v 1.73 2013/04/16 18:46:28 roberto Exp roberto $ | 2 | ** $Id: llex.h,v 1.74 2013/04/26 13:07:53 roberto Exp roberto $ |
| 3 | ** Lexical Analyzer | 3 | ** Lexical Analyzer |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -60,6 +60,7 @@ typedef struct LexState { | |||
| 60 | struct lua_State *L; | 60 | struct lua_State *L; |
| 61 | ZIO *z; /* input stream */ | 61 | ZIO *z; /* input stream */ |
| 62 | Mbuffer *buff; /* buffer for tokens */ | 62 | Mbuffer *buff; /* buffer for tokens */ |
| 63 | Table *h; /* to avoid collection/reuse strings */ | ||
| 63 | struct Dyndata *dyd; /* dynamic structures used by the parser */ | 64 | struct Dyndata *dyd; /* dynamic structures used by the parser */ |
| 64 | TString *source; /* current source name */ | 65 | TString *source; /* current source name */ |
| 65 | TString *envn; /* environment variable name */ | 66 | TString *envn; /* environment variable name */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.c,v 2.133 2013/04/26 13:07:53 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 2.134 2013/08/16 18:55:49 roberto Exp roberto $ |
| 3 | ** Lua Parser | 3 | ** Lua Parser |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -35,6 +35,10 @@ | |||
| 35 | #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) | 35 | #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) |
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | /* because all strings are unified by the scanner, the parser | ||
| 39 | can use pointer equality for string equality */ | ||
| 40 | #define eqstr(a,b) ((a) == (b)) | ||
| 41 | |||
| 38 | 42 | ||
| 39 | /* | 43 | /* |
| 40 | ** nodes for block list (list of active blocks) | 44 | ** nodes for block list (list of active blocks) |
| @@ -57,16 +61,6 @@ static void statement (LexState *ls); | |||
| 57 | static void expr (LexState *ls, expdesc *v); | 61 | static void expr (LexState *ls, expdesc *v); |
| 58 | 62 | ||
| 59 | 63 | ||
| 60 | static void anchor_token (LexState *ls) { | ||
| 61 | /* last token from outer function must be EOS */ | ||
| 62 | lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); | ||
| 63 | if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { | ||
| 64 | TString *ts = ls->t.seminfo.ts; | ||
| 65 | luaX_newstring(ls, getstr(ts), ts->tsv.len); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | |||
| 70 | /* semantic error */ | 64 | /* semantic error */ |
| 71 | static l_noret semerror (LexState *ls, const char *msg) { | 65 | static l_noret semerror (LexState *ls, const char *msg) { |
| 72 | ls->t.token = 0; /* remove 'near to' from final message */ | 66 | ls->t.token = 0; /* remove 'near to' from final message */ |
| @@ -222,7 +216,7 @@ static int searchupvalue (FuncState *fs, TString *name) { | |||
| 222 | int i; | 216 | int i; |
| 223 | Upvaldesc *up = fs->f->upvalues; | 217 | Upvaldesc *up = fs->f->upvalues; |
| 224 | for (i = 0; i < fs->nups; i++) { | 218 | for (i = 0; i < fs->nups; i++) { |
| 225 | if (luaS_eqstr(up[i].name, name)) return i; | 219 | if (eqstr(up[i].name, name)) return i; |
| 226 | } | 220 | } |
| 227 | return -1; /* not found */ | 221 | return -1; /* not found */ |
| 228 | } | 222 | } |
| @@ -246,7 +240,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { | |||
| 246 | static int searchvar (FuncState *fs, TString *n) { | 240 | static int searchvar (FuncState *fs, TString *n) { |
| 247 | int i; | 241 | int i; |
| 248 | for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { | 242 | for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { |
| 249 | if (luaS_eqstr(n, getlocvar(fs, i)->varname)) | 243 | if (eqstr(n, getlocvar(fs, i)->varname)) |
| 250 | return i; | 244 | return i; |
| 251 | } | 245 | } |
| 252 | return -1; /* not found */ | 246 | return -1; /* not found */ |
| @@ -342,7 +336,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { | |||
| 342 | FuncState *fs = ls->fs; | 336 | FuncState *fs = ls->fs; |
| 343 | Labellist *gl = &ls->dyd->gt; | 337 | Labellist *gl = &ls->dyd->gt; |
| 344 | Labeldesc *gt = &gl->arr[g]; | 338 | Labeldesc *gt = &gl->arr[g]; |
| 345 | lua_assert(luaS_eqstr(gt->name, label->name)); | 339 | lua_assert(eqstr(gt->name, label->name)); |
| 346 | if (gt->nactvar < label->nactvar) { | 340 | if (gt->nactvar < label->nactvar) { |
| 347 | TString *vname = getlocvar(fs, gt->nactvar)->varname; | 341 | TString *vname = getlocvar(fs, gt->nactvar)->varname; |
| 348 | const char *msg = luaO_pushfstring(ls->L, | 342 | const char *msg = luaO_pushfstring(ls->L, |
| @@ -369,7 +363,7 @@ static int findlabel (LexState *ls, int g) { | |||
| 369 | /* check labels in current block for a match */ | 363 | /* check labels in current block for a match */ |
| 370 | for (i = bl->firstlabel; i < dyd->label.n; i++) { | 364 | for (i = bl->firstlabel; i < dyd->label.n; i++) { |
| 371 | Labeldesc *lb = &dyd->label.arr[i]; | 365 | Labeldesc *lb = &dyd->label.arr[i]; |
| 372 | if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */ | 366 | if (eqstr(lb->name, gt->name)) { /* correct label? */ |
| 373 | if (gt->nactvar > lb->nactvar && | 367 | if (gt->nactvar > lb->nactvar && |
| 374 | (bl->upval || dyd->label.n > bl->firstlabel)) | 368 | (bl->upval || dyd->label.n > bl->firstlabel)) |
| 375 | luaK_patchclose(ls->fs, gt->pc, lb->nactvar); | 369 | luaK_patchclose(ls->fs, gt->pc, lb->nactvar); |
| @@ -403,7 +397,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { | |||
| 403 | Labellist *gl = &ls->dyd->gt; | 397 | Labellist *gl = &ls->dyd->gt; |
| 404 | int i = ls->fs->bl->firstgoto; | 398 | int i = ls->fs->bl->firstgoto; |
| 405 | while (i < gl->n) { | 399 | while (i < gl->n) { |
| 406 | if (luaS_eqstr(gl->arr[i].name, lb->name)) | 400 | if (eqstr(gl->arr[i].name, lb->name)) |
| 407 | closegoto(ls, i, lb); | 401 | closegoto(ls, i, lb); |
| 408 | else | 402 | else |
| 409 | i++; | 403 | i++; |
| @@ -525,7 +519,6 @@ static void codeclosure (LexState *ls, expdesc *v) { | |||
| 525 | 519 | ||
| 526 | 520 | ||
| 527 | static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { | 521 | static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { |
| 528 | lua_State *L = ls->L; | ||
| 529 | Proto *f; | 522 | Proto *f; |
| 530 | fs->prev = ls->fs; /* linked list of funcstates */ | 523 | fs->prev = ls->fs; /* linked list of funcstates */ |
| 531 | fs->ls = ls; | 524 | fs->ls = ls; |
| @@ -544,10 +537,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { | |||
| 544 | f = fs->f; | 537 | f = fs->f; |
| 545 | f->source = ls->source; | 538 | f->source = ls->source; |
| 546 | f->maxstacksize = 2; /* registers 0/1 are always valid */ | 539 | f->maxstacksize = 2; /* registers 0/1 are always valid */ |
| 547 | fs->h = luaH_new(L); | ||
| 548 | /* anchor table of constants (to avoid being collected) */ | ||
| 549 | sethvalue2s(L, L->top, fs->h); | ||
| 550 | incr_top(L); | ||
| 551 | enterblock(fs, bl, 0); | 540 | enterblock(fs, bl, 0); |
| 552 | } | 541 | } |
| 553 | 542 | ||
| @@ -572,9 +561,6 @@ static void close_func (LexState *ls) { | |||
| 572 | f->sizeupvalues = fs->nups; | 561 | f->sizeupvalues = fs->nups; |
| 573 | lua_assert(fs->bl == NULL); | 562 | lua_assert(fs->bl == NULL); |
| 574 | ls->fs = fs->prev; | 563 | ls->fs = fs->prev; |
| 575 | /* last token read was anchored in defunct function; must re-anchor it */ | ||
| 576 | anchor_token(ls); | ||
| 577 | L->top--; /* pop table of constants */ | ||
| 578 | luaC_checkGC(L); | 564 | luaC_checkGC(L); |
| 579 | } | 565 | } |
| 580 | 566 | ||
| @@ -1202,7 +1188,7 @@ static void gotostat (LexState *ls, int pc) { | |||
| 1202 | static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { | 1188 | static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { |
| 1203 | int i; | 1189 | int i; |
| 1204 | for (i = fs->bl->firstlabel; i < ll->n; i++) { | 1190 | for (i = fs->bl->firstlabel; i < ll->n; i++) { |
| 1205 | if (luaS_eqstr(label, ll->arr[i].name)) { | 1191 | if (eqstr(label, ll->arr[i].name)) { |
| 1206 | const char *msg = luaO_pushfstring(fs->ls->L, | 1192 | const char *msg = luaO_pushfstring(fs->ls->L, |
| 1207 | "label " LUA_QS " already defined on line %d", | 1193 | "label " LUA_QS " already defined on line %d", |
| 1208 | getstr(label), ll->arr[i].line); | 1194 | getstr(label), ll->arr[i].line); |
| @@ -1627,8 +1613,10 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, | |||
| 1627 | LexState lexstate; | 1613 | LexState lexstate; |
| 1628 | FuncState funcstate; | 1614 | FuncState funcstate; |
| 1629 | Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ | 1615 | Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ |
| 1630 | /* anchor closure (to avoid being collected) */ | 1616 | setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ |
| 1631 | setclLvalue(L, L->top, cl); | 1617 | incr_top(L); |
| 1618 | lexstate.h = luaH_new(L); /* create table for scanner */ | ||
| 1619 | sethvalue(L, L->top, lexstate.h); /* anchor it */ | ||
| 1632 | incr_top(L); | 1620 | incr_top(L); |
| 1633 | funcstate.f = cl->l.p = luaF_newproto(L); | 1621 | funcstate.f = cl->l.p = luaF_newproto(L); |
| 1634 | funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ | 1622 | funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ |
| @@ -1641,6 +1629,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, | |||
| 1641 | lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); | 1629 | lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); |
| 1642 | /* all scopes should be correctly finished */ | 1630 | /* all scopes should be correctly finished */ |
| 1643 | lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); | 1631 | lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); |
| 1644 | return cl; /* it's on the stack too */ | 1632 | L->top--; /* remove scanner's table */ |
| 1633 | return cl; /* closure is on the stack, too */ | ||
| 1645 | } | 1634 | } |
| 1646 | 1635 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.h,v 1.70 2012/05/08 13:53:33 roberto Exp roberto $ | 2 | ** $Id: lparser.h,v 1.71 2013/04/16 18:46:28 roberto Exp roberto $ |
| 3 | ** Lua Parser | 3 | ** Lua Parser |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -97,7 +97,6 @@ struct BlockCnt; /* defined in lparser.c */ | |||
| 97 | /* state needed to generate code for a given function */ | 97 | /* state needed to generate code for a given function */ |
| 98 | typedef struct FuncState { | 98 | typedef struct FuncState { |
| 99 | Proto *f; /* current function header */ | 99 | Proto *f; /* current function header */ |
| 100 | Table *h; /* table to find (and reuse) elements in `k' */ | ||
| 101 | struct FuncState *prev; /* enclosing function */ | 100 | struct FuncState *prev; /* enclosing function */ |
| 102 | struct LexState *ls; /* lexical state */ | 101 | struct LexState *ls; /* lexical state */ |
| 103 | struct BlockCnt *bl; /* chain of current blocks */ | 102 | struct BlockCnt *bl; /* chain of current blocks */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltable.h,v 2.16 2011/08/17 20:26:47 roberto Exp roberto $ | 2 | ** $Id: ltable.h,v 2.17 2013/04/26 15:39:25 roberto Exp roberto $ |
| 3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -18,6 +18,11 @@ | |||
| 18 | #define invalidateTMcache(t) ((t)->flags = 0) | 18 | #define invalidateTMcache(t) ((t)->flags = 0) |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | /* returns the key, given the value of a table entry */ | ||
| 22 | #define keyfromval(v) \ | ||
| 23 | (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) | ||
| 24 | |||
| 25 | |||
| 21 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); | 26 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); |
| 22 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, | 27 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, |
| 23 | TValue *value); | 28 | TValue *value); |
