diff options
-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 |