diff options
Diffstat (limited to '')
| -rw-r--r-- | lcode.c | 4 | ||||
| -rw-r--r-- | ldo.c | 3 | ||||
| -rw-r--r-- | lgc.c | 4 | ||||
| -rw-r--r-- | ljumptab.h | 1 | ||||
| -rw-r--r-- | lobject.h | 4 | ||||
| -rw-r--r-- | lopcodes.c | 1 | ||||
| -rw-r--r-- | lopcodes.h | 1 | ||||
| -rw-r--r-- | lopnames.h | 1 | ||||
| -rw-r--r-- | lparser.c | 34 | ||||
| -rw-r--r-- | lparser.h | 1 | ||||
| -rw-r--r-- | lstate.h | 3 | ||||
| -rw-r--r-- | ltests.c | 25 | ||||
| -rw-r--r-- | lvm.c | 6 | ||||
| -rw-r--r-- | testes/code.lua | 6 | ||||
| -rw-r--r-- | testes/locals.lua | 9 |
15 files changed, 81 insertions, 22 deletions
| @@ -1673,13 +1673,13 @@ void luaK_finish (FuncState *fs) { | |||
| 1673 | lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); | 1673 | lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); |
| 1674 | switch (GET_OPCODE(*pc)) { | 1674 | switch (GET_OPCODE(*pc)) { |
| 1675 | case OP_RETURN0: case OP_RETURN1: { | 1675 | case OP_RETURN0: case OP_RETURN1: { |
| 1676 | if (p->sizep == 0 && !p->is_vararg) | 1676 | if (!(fs->needclose || p->is_vararg)) |
| 1677 | break; /* no extra work */ | 1677 | break; /* no extra work */ |
| 1678 | /* else use OP_RETURN to do the extra work */ | 1678 | /* else use OP_RETURN to do the extra work */ |
| 1679 | SET_OPCODE(*pc, OP_RETURN); | 1679 | SET_OPCODE(*pc, OP_RETURN); |
| 1680 | } /* FALLTHROUGH */ | 1680 | } /* FALLTHROUGH */ |
| 1681 | case OP_RETURN: case OP_TAILCALL: { | 1681 | case OP_RETURN: case OP_TAILCALL: { |
| 1682 | if (p->sizep > 0 || p->is_vararg) { | 1682 | if (fs->needclose || p->is_vararg) { |
| 1683 | SETARG_C(*pc, p->is_vararg ? p->numparams + 1 : 0); | 1683 | SETARG_C(*pc, p->is_vararg ? p->numparams + 1 : 0); |
| 1684 | SETARG_k(*pc, 1); /* signal that there is extra work */ | 1684 | SETARG_k(*pc, 1); /* signal that there is extra work */ |
| 1685 | } | 1685 | } |
| @@ -91,8 +91,7 @@ struct lua_longjmp { | |||
| 91 | static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { | 91 | static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { |
| 92 | switch (errcode) { | 92 | switch (errcode) { |
| 93 | case LUA_ERRMEM: { /* memory error? */ | 93 | case LUA_ERRMEM: { /* memory error? */ |
| 94 | TString *memerrmsg = luaS_newliteral(L, MEMERRMSG); | 94 | setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ |
| 95 | setsvalue2s(L, oldtop, memerrmsg); /* reuse preregistered msg. */ | ||
| 96 | break; | 95 | break; |
| 97 | } | 96 | } |
| 98 | case LUA_ERRERR: { | 97 | case LUA_ERRERR: { |
| @@ -293,7 +293,8 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 293 | gray2black(o); | 293 | gray2black(o); |
| 294 | break; | 294 | break; |
| 295 | } | 295 | } |
| 296 | case LUA_TUPVAL: { | 296 | case LUA_TUPVAL: |
| 297 | case LUA_TUPVALTBC: { | ||
| 297 | UpVal *uv = gco2upv(o); | 298 | UpVal *uv = gco2upv(o); |
| 298 | if (!upisopen(uv)) /* open upvalues are kept gray */ | 299 | if (!upisopen(uv)) /* open upvalues are kept gray */ |
| 299 | gray2black(o); | 300 | gray2black(o); |
| @@ -760,6 +761,7 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 760 | luaF_freeproto(L, gco2p(o)); | 761 | luaF_freeproto(L, gco2p(o)); |
| 761 | break; | 762 | break; |
| 762 | case LUA_TUPVAL: | 763 | case LUA_TUPVAL: |
| 764 | case LUA_TUPVALTBC: | ||
| 763 | freeupval(L, gco2upv(o)); | 765 | freeupval(L, gco2upv(o)); |
| 764 | break; | 766 | break; |
| 765 | case LUA_TLCL: | 767 | case LUA_TLCL: |
| @@ -74,6 +74,7 @@ static void *disptab[] = { | |||
| 74 | &&L_OP_LEN, | 74 | &&L_OP_LEN, |
| 75 | &&L_OP_CONCAT, | 75 | &&L_OP_CONCAT, |
| 76 | &&L_OP_CLOSE, | 76 | &&L_OP_CLOSE, |
| 77 | &&L_OP_TBC, | ||
| 77 | &&L_OP_JMP, | 78 | &&L_OP_JMP, |
| 78 | &&L_OP_EQ, | 79 | &&L_OP_EQ, |
| 79 | &&L_OP_LT, | 80 | &&L_OP_LT, |
| @@ -588,6 +588,10 @@ typedef struct UpVal { | |||
| 588 | } UpVal; | 588 | } UpVal; |
| 589 | 589 | ||
| 590 | 590 | ||
| 591 | /* variant for "To Be Closed" upvalues */ | ||
| 592 | #define LUA_TUPVALTBC (LUA_TUPVAL | (1 << 4)) | ||
| 593 | |||
| 594 | |||
| 591 | #define ClosureHeader \ | 595 | #define ClosureHeader \ |
| 592 | CommonHeader; lu_byte nupvalues; GCObject *gclist | 596 | CommonHeader; lu_byte nupvalues; GCObject *gclist |
| 593 | 597 | ||
| @@ -68,6 +68,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { | |||
| 68 | ,opmode(0, 0, 0, 1, iABC) /* OP_LEN */ | 68 | ,opmode(0, 0, 0, 1, iABC) /* OP_LEN */ |
| 69 | ,opmode(0, 0, 0, 1, iABC) /* OP_CONCAT */ | 69 | ,opmode(0, 0, 0, 1, iABC) /* OP_CONCAT */ |
| 70 | ,opmode(0, 0, 0, 0, iABC) /* OP_CLOSE */ | 70 | ,opmode(0, 0, 0, 0, iABC) /* OP_CLOSE */ |
| 71 | ,opmode(0, 0, 0, 0, iABC) /* OP_TBC */ | ||
| 71 | ,opmode(0, 0, 0, 0, isJ) /* OP_JMP */ | 72 | ,opmode(0, 0, 0, 0, isJ) /* OP_JMP */ |
| 72 | ,opmode(0, 0, 1, 0, iABC) /* OP_EQ */ | 73 | ,opmode(0, 0, 1, 0, iABC) /* OP_EQ */ |
| 73 | ,opmode(0, 0, 1, 0, iABC) /* OP_LT */ | 74 | ,opmode(0, 0, 1, 0, iABC) /* OP_LT */ |
| @@ -251,6 +251,7 @@ OP_LEN,/* A B R(A) := length of R(B) */ | |||
| 251 | OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */ | 251 | OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */ |
| 252 | 252 | ||
| 253 | OP_CLOSE,/* A close all upvalues >= R(A) */ | 253 | OP_CLOSE,/* A close all upvalues >= R(A) */ |
| 254 | OP_TBC,/* A mark variable A "to be closed" */ | ||
| 254 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ | 255 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ |
| 255 | OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */ | 256 | OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */ |
| 256 | OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */ | 257 | OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */ |
| @@ -59,6 +59,7 @@ static const char *const opnames[] = { | |||
| 59 | "LEN", | 59 | "LEN", |
| 60 | "CONCAT", | 60 | "CONCAT", |
| 61 | "CLOSE", | 61 | "CLOSE", |
| 62 | "TBC", | ||
| 62 | "JMP", | 63 | "JMP", |
| 63 | "EQ", | 64 | "EQ", |
| 64 | "LT", | 65 | "LT", |
| @@ -255,6 +255,7 @@ static void markupval (FuncState *fs, int level) { | |||
| 255 | while (bl->nactvar > level) | 255 | while (bl->nactvar > level) |
| 256 | bl = bl->previous; | 256 | bl = bl->previous; |
| 257 | bl->upval = 1; | 257 | bl->upval = 1; |
| 258 | fs->needclose = 1; | ||
| 258 | } | 259 | } |
| 259 | 260 | ||
| 260 | 261 | ||
| @@ -547,6 +548,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { | |||
| 547 | fs->nups = 0; | 548 | fs->nups = 0; |
| 548 | fs->nlocvars = 0; | 549 | fs->nlocvars = 0; |
| 549 | fs->nactvar = 0; | 550 | fs->nactvar = 0; |
| 551 | fs->needclose = 0; | ||
| 550 | fs->firstlocal = ls->dyd->actvar.n; | 552 | fs->firstlocal = ls->dyd->actvar.n; |
| 551 | fs->bl = NULL; | 553 | fs->bl = NULL; |
| 552 | f->source = ls->source; | 554 | f->source = ls->source; |
| @@ -1509,15 +1511,16 @@ static void localfunc (LexState *ls) { | |||
| 1509 | } | 1511 | } |
| 1510 | 1512 | ||
| 1511 | 1513 | ||
| 1512 | static void localstat (LexState *ls) { | 1514 | static void commonlocalstat (LexState *ls, TString *firstvar) { |
| 1513 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ | 1515 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ |
| 1514 | int nvars = 0; | 1516 | int nvars = 1; |
| 1515 | int nexps; | 1517 | int nexps; |
| 1516 | expdesc e; | 1518 | expdesc e; |
| 1517 | do { | 1519 | new_localvar(ls, firstvar); |
| 1520 | while (testnext(ls, ',')) { | ||
| 1518 | new_localvar(ls, str_checkname(ls)); | 1521 | new_localvar(ls, str_checkname(ls)); |
| 1519 | nvars++; | 1522 | nvars++; |
| 1520 | } while (testnext(ls, ',')); | 1523 | } |
| 1521 | if (testnext(ls, '=')) | 1524 | if (testnext(ls, '=')) |
| 1522 | nexps = explist(ls, &e); | 1525 | nexps = explist(ls, &e); |
| 1523 | else { | 1526 | else { |
| @@ -1529,6 +1532,29 @@ static void localstat (LexState *ls) { | |||
| 1529 | } | 1532 | } |
| 1530 | 1533 | ||
| 1531 | 1534 | ||
| 1535 | static void scopedlocalstat (LexState *ls) { | ||
| 1536 | FuncState *fs = ls->fs; | ||
| 1537 | new_localvar(ls, str_checkname(ls)); | ||
| 1538 | checknext(ls, '='); | ||
| 1539 | luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0); | ||
| 1540 | markupval(fs, fs->nactvar); | ||
| 1541 | exp1(ls, 0); | ||
| 1542 | adjustlocalvars(ls, 1); | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | |||
| 1546 | static void localstat (LexState *ls) { | ||
| 1547 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] | ||
| 1548 | | LOCAL SCOPED NAME '=' exp */ | ||
| 1549 | TString *firstvar = str_checkname(ls); | ||
| 1550 | if (ls->t.token == TK_NAME && | ||
| 1551 | eqshrstr(firstvar, luaS_newliteral(ls->L, "scoped"))) | ||
| 1552 | scopedlocalstat(ls); | ||
| 1553 | else | ||
| 1554 | commonlocalstat(ls, firstvar); | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | |||
| 1532 | static int funcname (LexState *ls, expdesc *v) { | 1558 | static int funcname (LexState *ls, expdesc *v) { |
| 1533 | /* funcname -> NAME {fieldsel} [':' NAME] */ | 1559 | /* funcname -> NAME {fieldsel} [':' NAME] */ |
| 1534 | int ismethod = 0; | 1560 | int ismethod = 0; |
| @@ -133,6 +133,7 @@ typedef struct FuncState { | |||
| 133 | lu_byte nups; /* number of upvalues */ | 133 | lu_byte nups; /* number of upvalues */ |
| 134 | lu_byte freereg; /* first free register */ | 134 | lu_byte freereg; /* first free register */ |
| 135 | lu_byte iwthabs; /* instructions issued since last absolute line info */ | 135 | lu_byte iwthabs; /* instructions issued since last absolute line info */ |
| 136 | lu_byte needclose; /* function needs to close upvalues when returning */ | ||
| 136 | } FuncState; | 137 | } FuncState; |
| 137 | 138 | ||
| 138 | 139 | ||
| @@ -267,7 +267,8 @@ union GCUnion { | |||
| 267 | #define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) | 267 | #define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) |
| 268 | #define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) | 268 | #define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) |
| 269 | #define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) | 269 | #define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) |
| 270 | #define gco2upv(o) check_exp((o)->tt == LUA_TUPVAL, &((cast_u(o))->upv)) | 270 | #define gco2upv(o) \ |
| 271 | check_exp(novariant((o)->tt) == LUA_TUPVAL, &((cast_u(o))->upv)) | ||
| 271 | 272 | ||
| 272 | 273 | ||
| 273 | /* | 274 | /* |
| @@ -357,7 +357,8 @@ static void checkrefs (global_State *g, GCObject *o) { | |||
| 357 | checkudata(g, gco2u(o)); | 357 | checkudata(g, gco2u(o)); |
| 358 | break; | 358 | break; |
| 359 | } | 359 | } |
| 360 | case LUA_TUPVAL: { | 360 | case LUA_TUPVAL: |
| 361 | case LUA_TUPVALTBC: { | ||
| 361 | checkvalref(g, o, gco2upv(o)->v); | 362 | checkvalref(g, o, gco2upv(o)->v); |
| 362 | break; | 363 | break; |
| 363 | } | 364 | } |
| @@ -522,35 +523,37 @@ int lua_checkmemory (lua_State *L) { | |||
| 522 | 523 | ||
| 523 | 524 | ||
| 524 | static char *buildop (Proto *p, int pc, char *buff) { | 525 | static char *buildop (Proto *p, int pc, char *buff) { |
| 526 | char *obuff = buff; | ||
| 525 | Instruction i = p->code[pc]; | 527 | Instruction i = p->code[pc]; |
| 526 | OpCode o = GET_OPCODE(i); | 528 | OpCode o = GET_OPCODE(i); |
| 527 | const char *name = opnames[o]; | 529 | const char *name = opnames[o]; |
| 528 | int line = luaG_getfuncline(p, pc); | 530 | int line = luaG_getfuncline(p, pc); |
| 529 | int lineinfo = (p->lineinfo != NULL) ? p->lineinfo[pc] : 0; | 531 | int lineinfo = (p->lineinfo != NULL) ? p->lineinfo[pc] : 0; |
| 530 | sprintf(buff, "(%2d - %4d) %4d - ", lineinfo, line, pc); | 532 | if (lineinfo == ABSLINEINFO) |
| 533 | buff += sprintf(buff, "(__"); | ||
| 534 | else | ||
| 535 | buff += sprintf(buff, "(%2d", lineinfo); | ||
| 536 | buff += sprintf(buff, " - %4d) %4d - ", line, pc); | ||
| 531 | switch (getOpMode(o)) { | 537 | switch (getOpMode(o)) { |
| 532 | case iABC: | 538 | case iABC: |
| 533 | sprintf(buff+strlen(buff), "%-12s%4d %4d %4d%s", name, | 539 | sprintf(buff, "%-12s%4d %4d %4d%s", name, |
| 534 | GETARG_A(i), GETARG_B(i), GETARG_C(i), | 540 | GETARG_A(i), GETARG_B(i), GETARG_C(i), |
| 535 | GETARG_k(i) ? " (k)" : ""); | 541 | GETARG_k(i) ? " (k)" : ""); |
| 536 | break; | 542 | break; |
| 537 | case iABx: | 543 | case iABx: |
| 538 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), | 544 | sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); |
| 539 | GETARG_Bx(i)); | ||
| 540 | break; | 545 | break; |
| 541 | case iAsBx: | 546 | case iAsBx: |
| 542 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), | 547 | sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); |
| 543 | GETARG_sBx(i)); | ||
| 544 | break; | 548 | break; |
| 545 | case iAx: | 549 | case iAx: |
| 546 | sprintf(buff+strlen(buff), "%-12s%4d", name, GETARG_Ax(i)); | 550 | sprintf(buff, "%-12s%4d", name, GETARG_Ax(i)); |
| 547 | break; | 551 | break; |
| 548 | case isJ: | 552 | case isJ: |
| 549 | sprintf(buff+strlen(buff), "%-12s%4d (%1d)", name, GETARG_sJ(i), | 553 | sprintf(buff, "%-12s%4d (%1d)", name, GETARG_sJ(i), !!GETARG_m(i)); |
| 550 | !!GETARG_m(i)); | ||
| 551 | break; | 554 | break; |
| 552 | } | 555 | } |
| 553 | return buff; | 556 | return obuff; |
| 554 | } | 557 | } |
| 555 | 558 | ||
| 556 | 559 | ||
| @@ -1455,6 +1455,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1455 | luaF_close(L, ra); | 1455 | luaF_close(L, ra); |
| 1456 | vmbreak; | 1456 | vmbreak; |
| 1457 | } | 1457 | } |
| 1458 | vmcase(OP_TBC) { | ||
| 1459 | UpVal *up = luaF_findupval(L, ra); /* create new upvalue */ | ||
| 1460 | up->tt = LUA_TUPVALTBC; /* mark it to be closed */ | ||
| 1461 | setnilvalue(s2v(ra)); /* intialize it with nil */ | ||
| 1462 | vmbreak; | ||
| 1463 | } | ||
| 1458 | vmcase(OP_JMP) { | 1464 | vmcase(OP_JMP) { |
| 1459 | dojump(ci, i, 0); | 1465 | dojump(ci, i, 0); |
| 1460 | vmbreak; | 1466 | vmbreak; |
diff --git a/testes/code.lua b/testes/code.lua index 6bd6ebfa..ad484485 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
| @@ -64,8 +64,12 @@ end | |||
| 64 | 64 | ||
| 65 | 65 | ||
| 66 | -- some basic instructions | 66 | -- some basic instructions |
| 67 | check(function () | 67 | check(function () -- function does not create upvalues |
| 68 | (function () end){f()} | 68 | (function () end){f()} |
| 69 | end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN0') | ||
| 70 | |||
| 71 | check(function (x) -- function creates upvalues | ||
| 72 | (function () return x end){f()} | ||
| 69 | end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') | 73 | end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') |
| 70 | 74 | ||
| 71 | 75 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index 14e49a7c..20ecae4b 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
| @@ -173,6 +173,15 @@ end | |||
| 173 | assert(x==20) | 173 | assert(x==20) |
| 174 | 174 | ||
| 175 | 175 | ||
| 176 | -- tests for to-be-closed variables | ||
| 177 | do | ||
| 178 | local scoped x = 3 | ||
| 179 | local a | ||
| 180 | local scoped y = 5 | ||
| 181 | assert(x == 3 and y == 5) | ||
| 182 | end | ||
| 183 | |||
| 184 | |||
| 176 | print('OK') | 185 | print('OK') |
| 177 | 186 | ||
| 178 | return 5,f | 187 | return 5,f |
