aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lcode.c4
-rw-r--r--ldo.c3
-rw-r--r--lgc.c4
-rw-r--r--ljumptab.h1
-rw-r--r--lobject.h4
-rw-r--r--lopcodes.c1
-rw-r--r--lopcodes.h1
-rw-r--r--lopnames.h1
-rw-r--r--lparser.c34
-rw-r--r--lparser.h1
-rw-r--r--lstate.h3
-rw-r--r--ltests.c25
-rw-r--r--lvm.c6
-rw-r--r--testes/code.lua6
-rw-r--r--testes/locals.lua9
15 files changed, 81 insertions, 22 deletions
diff --git a/lcode.c b/lcode.c
index d00038dd..e84b85ac 100644
--- a/lcode.c
+++ b/lcode.c
@@ -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 }
diff --git a/ldo.c b/ldo.c
index 0d68d36c..2349aaed 100644
--- a/ldo.c
+++ b/ldo.c
@@ -91,8 +91,7 @@ struct lua_longjmp {
91static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { 91static 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: {
diff --git a/lgc.c b/lgc.c
index e8429e1b..39b3ab73 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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:
diff --git a/ljumptab.h b/ljumptab.h
index c775f10a..da4cf7b7 100644
--- a/ljumptab.h
+++ b/ljumptab.h
@@ -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,
diff --git a/lobject.h b/lobject.h
index ddcf609c..ea3511de 100644
--- a/lobject.h
+++ b/lobject.h
@@ -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
diff --git a/lopcodes.c b/lopcodes.c
index 95347b27..f6915beb 100644
--- a/lopcodes.c
+++ b/lopcodes.c
@@ -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 */
diff --git a/lopcodes.h b/lopcodes.h
index 9442a336..4d144000 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -251,6 +251,7 @@ OP_LEN,/* A B R(A) := length of R(B) */
251OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */ 251OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */
252 252
253OP_CLOSE,/* A close all upvalues >= R(A) */ 253OP_CLOSE,/* A close all upvalues >= R(A) */
254OP_TBC,/* A mark variable A "to be closed" */
254OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ 255OP_JMP,/* k sJ pc += sJ (k is used in code generation) */
255OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */ 256OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */
256OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */ 257OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */
diff --git a/lopnames.h b/lopnames.h
index c40eaeae..304d3b6c 100644
--- a/lopnames.h
+++ b/lopnames.h
@@ -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",
diff --git a/lparser.c b/lparser.c
index 32500b02..84abeb90 100644
--- a/lparser.c
+++ b/lparser.c
@@ -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
1512static void localstat (LexState *ls) { 1514static 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
1535static 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
1546static 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
1532static int funcname (LexState *ls, expdesc *v) { 1558static int funcname (LexState *ls, expdesc *v) {
1533 /* funcname -> NAME {fieldsel} [':' NAME] */ 1559 /* funcname -> NAME {fieldsel} [':' NAME] */
1534 int ismethod = 0; 1560 int ismethod = 0;
diff --git a/lparser.h b/lparser.h
index e158c9d9..1b94a97a 100644
--- a/lparser.h
+++ b/lparser.h
@@ -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
diff --git a/lstate.h b/lstate.h
index 5461b291..f08c2355 100644
--- a/lstate.h
+++ b/lstate.h
@@ -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/*
diff --git a/ltests.c b/ltests.c
index bc71d937..ff962543 100644
--- a/ltests.c
+++ b/ltests.c
@@ -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
524static char *buildop (Proto *p, int pc, char *buff) { 525static 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
diff --git a/lvm.c b/lvm.c
index dd6a660b..fdd99a42 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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
67check(function () 67check(function () -- function does not create upvalues
68 (function () end){f()} 68 (function () end){f()}
69end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN0')
70
71check(function (x) -- function creates upvalues
72 (function () return x end){f()}
69end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') 73end, '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
173assert(x==20) 173assert(x==20)
174 174
175 175
176-- tests for to-be-closed variables
177do
178 local scoped x = 3
179 local a
180 local scoped y = 5
181 assert(x == 3 and y == 5)
182end
183
184
176print('OK') 185print('OK')
177 186
178return 5,f 187return 5,f