aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-09-13 16:50:08 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-09-13 16:50:08 -0300
commit80d9b09f351c7a9be557116e9c79ae11e9b3f032 (patch)
treea6ae7cce019e85c2f79987035c77d4e4213d07a9
parent029d269f4d1afd0e9ea0f889eb3e65a7f0fab0f9 (diff)
downloadlua-80d9b09f351c7a9be557116e9c79ae11e9b3f032.tar.gz
lua-80d9b09f351c7a9be557116e9c79ae11e9b3f032.tar.bz2
lua-80d9b09f351c7a9be557116e9c79ae11e9b3f032.zip
jumps do not close upvalues (to be faster and simpler);
explicit instruction to close upvalues; command 'break' not handled like a 'goto' (to optimize removal of uneeded 'close' instructions)
-rw-r--r--lcode.c51
-rw-r--r--lcode.h6
-rw-r--r--lopcodes.c6
-rw-r--r--lopcodes.h5
-rw-r--r--lparser.c127
-rw-r--r--lvm.c11
6 files changed, 139 insertions, 67 deletions
diff --git a/lcode.c b/lcode.c
index 169c439d..1edf08aa 100644
--- a/lcode.c
+++ b/lcode.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lcode.c,v 2.120 2017/06/27 11:35:31 roberto Exp roberto $ 2** $Id: lcode.c,v 2.121 2017/06/29 15:06:44 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*/
@@ -272,20 +272,51 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
272 272
273 273
274/* 274/*
275** Path all jumps in 'list' to close upvalues up to given 'level' 275** Check whether some jump in given list needs a close instruction.
276** (The assertion checks that jumps either were closing nothing
277** or were closing higher levels, from inner blocks.)
278*/ 276*/
279void luaK_patchclose (FuncState *fs, int list, int level) { 277int luaK_needclose (FuncState *fs, int list) {
280 level++; /* argument is +1 to reserve 0 as non-op */
281 for (; list != NO_JUMP; list = getjump(fs, list)) { 278 for (; list != NO_JUMP; list = getjump(fs, list)) {
282 lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && 279 if (GETARG_A(fs->f->code[list])) /* needs close? */
283 (GETARG_A(fs->f->code[list]) == 0 || 280 return 1;
284 GETARG_A(fs->f->code[list]) >= level)); 281 }
285 SETARG_A(fs->f->code[list], level); 282 return 0;
283}
284
285
286/*
287** Correct a jump list to jump to 'target'. If 'hasclose' is true,
288** 'target' contains an OP_CLOSE instruction (see first assert).
289** Only jumps with the A arg true need that close; other jumps
290** avoid it jumping to the next instruction.
291*/
292void luaK_patchgoto (FuncState *fs, int list, int target, int hasclose) {
293 lua_assert(!hasclose || GET_OPCODE(fs->f->code[target]) == OP_CLOSE);
294 while (list != NO_JUMP) {
295 int next = getjump(fs, list);
296 lua_assert(!GETARG_A(fs->f->code[list]) || hasclose);
297 patchtestreg(fs, list, NO_REG); /* do not generate values */
298 if (!hasclose || GETARG_A(fs->f->code[list]))
299 fixjump(fs, list, target);
300 else /* there is a CLOSE instruction but jump does not need it */
301 fixjump(fs, list, target + 1); /* avoid CLOSE instruction */
302 list = next;
286 } 303 }
287} 304}
288 305
306
307/*
308** Mark (using the A arg) all jumps in 'list' to close upvalues. Mark
309** will instruct 'luaK_patchgoto' to make these jumps go to OP_CLOSE
310** instructions.
311*/
312void luaK_patchclose (FuncState *fs, int list) {
313 for (; list != NO_JUMP; list = getjump(fs, list)) {
314 lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP);
315 SETARG_A(fs->f->code[list], 1);
316 }
317}
318
319
289#if !defined(MAXIWTHABS) 320#if !defined(MAXIWTHABS)
290#define MAXIWTHABS 120 321#define MAXIWTHABS 120
291#endif 322#endif
diff --git a/lcode.h b/lcode.h
index e7ff3522..70953559 100644
--- a/lcode.h
+++ b/lcode.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp roberto $ 2** $Id: lcode.h,v 1.65 2017/04/20 19:53:55 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*/
@@ -73,8 +73,10 @@ LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
73LUAI_FUNC int luaK_jump (FuncState *fs); 73LUAI_FUNC int luaK_jump (FuncState *fs);
74LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); 74LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
75LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); 75LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
76void luaK_patchgoto (FuncState *fs, int list, int target, int hasclose);
76LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); 77LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
77LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); 78LUAI_FUNC void luaK_patchclose (FuncState *fs, int list);
79LUAI_FUNC int luaK_needclose (FuncState *fs, int list);
78LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); 80LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
79LUAI_FUNC int luaK_getlabel (FuncState *fs); 81LUAI_FUNC int luaK_getlabel (FuncState *fs);
80LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); 82LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
diff --git a/lopcodes.c b/lopcodes.c
index 74195d42..a64c29ce 100644
--- a/lopcodes.c
+++ b/lopcodes.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lopcodes.c,v 1.59 2017/06/29 15:38:41 roberto Exp roberto $ 2** $Id: lopcodes.c,v 1.60 2017/08/14 18:33:14 roberto Exp roberto $
3** Opcodes for Lua virtual machine 3** Opcodes for Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -54,6 +54,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
54 "NOT", 54 "NOT",
55 "LEN", 55 "LEN",
56 "CONCAT", 56 "CONCAT",
57 "CLOSE",
57 "JMP", 58 "JMP",
58 "EQ", 59 "EQ",
59 "LT", 60 "LT",
@@ -115,7 +116,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
115 ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ 116 ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */
116 ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ 117 ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */
117 ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ 118 ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */
118 ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ 119 ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */
120 ,opmode(0, 0, OpArgU, OpArgN, iAsBx) /* OP_JMP */
119 ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ 121 ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */
120 ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ 122 ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */
121 ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ 123 ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */
diff --git a/lopcodes.h b/lopcodes.h
index f35de02a..4dfe66ce 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lopcodes.h,v 1.155 2017/06/29 15:38:41 roberto Exp roberto $ 2** $Id: lopcodes.h,v 1.156 2017/08/14 18:33:14 roberto Exp roberto $
3** Opcodes for Lua virtual machine 3** Opcodes for Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -217,7 +217,8 @@ OP_LEN,/* A B R(A) := length of R(B) */
217 217
218OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ 218OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
219 219
220OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ 220OP_CLOSE,/* A close all upvalues >= R(A) */
221OP_JMP,/* sBx pc+=sBx */
221OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ 222OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
222OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ 223OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
223OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ 224OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
diff --git a/lparser.c b/lparser.c
index 2eb5581f..7fd62f50 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lparser.c,v 2.163 2017/08/12 13:12:21 roberto Exp roberto $ 2** $Id: lparser.c,v 2.164 2017/08/14 18:33:14 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*/
@@ -49,6 +49,8 @@ typedef struct BlockCnt {
49 struct BlockCnt *previous; /* chain */ 49 struct BlockCnt *previous; /* chain */
50 int firstlabel; /* index of first label in this block */ 50 int firstlabel; /* index of first label in this block */
51 int firstgoto; /* index of first pending goto in this block */ 51 int firstgoto; /* index of first pending goto in this block */
52 int brks; /* list of break jumps in this block */
53 lu_byte brkcls; /* true if some 'break' needs to close upvalues */
52 lu_byte nactvar; /* # active locals outside the block */ 54 lu_byte nactvar; /* # active locals outside the block */
53 lu_byte upval; /* true if some variable in the block is an upvalue */ 55 lu_byte upval; /* true if some variable in the block is an upvalue */
54 lu_byte isloop; /* true if 'block' is a loop */ 56 lu_byte isloop; /* true if 'block' is a loop */
@@ -351,7 +353,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
351 getstr(gt->name), gt->line, getstr(vname)); 353 getstr(gt->name), gt->line, getstr(vname));
352 semerror(ls, msg); 354 semerror(ls, msg);
353 } 355 }
354 luaK_patchlist(fs, gt->pc, label->pc); 356 luaK_patchgoto(fs, gt->pc, label->pc, 1);
355 /* remove goto from pending list */ 357 /* remove goto from pending list */
356 for (i = g; i < gl->n - 1; i++) 358 for (i = g; i < gl->n - 1; i++)
357 gl->arr[i] = gl->arr[i + 1]; 359 gl->arr[i] = gl->arr[i + 1];
@@ -362,7 +364,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
362/* 364/*
363** try to close a goto with existing labels; this solves backward jumps 365** try to close a goto with existing labels; this solves backward jumps
364*/ 366*/
365static int findlabel (LexState *ls, int g) { 367static int solvelabel (LexState *ls, int g) {
366 int i; 368 int i;
367 BlockCnt *bl = ls->fs->bl; 369 BlockCnt *bl = ls->fs->bl;
368 Dyndata *dyd = ls->dyd; 370 Dyndata *dyd = ls->dyd;
@@ -373,7 +375,7 @@ static int findlabel (LexState *ls, int g) {
373 if (eqstr(lb->name, gt->name)) { /* correct label? */ 375 if (eqstr(lb->name, gt->name)) { /* correct label? */
374 if (gt->nactvar > lb->nactvar && 376 if (gt->nactvar > lb->nactvar &&
375 (bl->upval || dyd->label.n > bl->firstlabel)) 377 (bl->upval || dyd->label.n > bl->firstlabel))
376 luaK_patchclose(ls->fs, gt->pc, lb->nactvar); 378 luaK_patchclose(ls->fs, gt->pc);
377 closegoto(ls, g, lb); /* close it */ 379 closegoto(ls, g, lb); /* close it */
378 return 1; 380 return 1;
379 } 381 }
@@ -400,12 +402,12 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name,
400** check whether new label 'lb' matches any pending gotos in current 402** check whether new label 'lb' matches any pending gotos in current
401** block; solves forward jumps 403** block; solves forward jumps
402*/ 404*/
403static void findgotos (LexState *ls, Labeldesc *lb) { 405static void solvegotos (LexState *ls, Labeldesc *lb) {
404 Labellist *gl = &ls->dyd->gt; 406 Labellist *gl = &ls->dyd->gt;
405 int i = ls->fs->bl->firstgoto; 407 int i = ls->fs->bl->firstgoto;
406 while (i < gl->n) { 408 while (i < gl->n) {
407 if (eqstr(gl->arr[i].name, lb->name)) 409 if (eqstr(gl->arr[i].name, lb->name))
408 closegoto(ls, i, lb); 410 closegoto(ls, i, lb); /* will remove 'i' from the list */
409 else 411 else
410 i++; 412 i++;
411 } 413 }
@@ -416,23 +418,32 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
416** export pending gotos to outer level, to check them against 418** export pending gotos to outer level, to check them against
417** outer labels; if the block being exited has upvalues, and 419** outer labels; if the block being exited has upvalues, and
418** the goto exits the scope of any variable (which can be the 420** the goto exits the scope of any variable (which can be the
419** upvalue), close those variables being exited. 421** upvalue), close those variables being exited. Also export
422** break list.
420*/ 423*/
421static void movegotosout (FuncState *fs, BlockCnt *bl) { 424static void movegotosout (FuncState *fs, BlockCnt *bl) {
422 int i = bl->firstgoto; 425 int i = bl->firstgoto;
423 Labellist *gl = &fs->ls->dyd->gt; 426 Labellist *gl = &fs->ls->dyd->gt;
424 /* correct pending gotos to current block and try to close it 427 /* correct pending gotos to current block and try to close it
425 with visible labels */ 428 with visible labels */
426 while (i < gl->n) { 429 while (i < gl->n) { /* for each pending goto */
427 Labeldesc *gt = &gl->arr[i]; 430 Labeldesc *gt = &gl->arr[i];
428 if (gt->nactvar > bl->nactvar) { 431 if (gt->nactvar > bl->nactvar) { /* leaving a variable scope? */
429 if (bl->upval) 432 if (bl->upval) /* variable may be an upvalue? */
430 luaK_patchclose(fs, gt->pc, bl->nactvar); 433 luaK_patchclose(fs, gt->pc); /* jump will need a close */
431 gt->nactvar = bl->nactvar; 434 gt->nactvar = bl->nactvar; /* update goto level */
432 } 435 }
433 if (!findlabel(fs->ls, i)) 436 if (!solvelabel(fs->ls, i))
434 i++; /* move to next one */ 437 i++; /* move to next one */
438 /* else, 'solvelabel' removed current goto from the list
439 and 'i' now points to next one */
435 } 440 }
441 /* handles break list */
442 if (bl->upval) /* exiting the scope of an upvalue? */
443 luaK_patchclose(fs, bl->brks); /* breaks will need OP_CLOSE */
444 /* move breaks to outer block */
445 luaK_concat(fs, &bl->previous->brks, bl->brks);
446 bl->previous->brkcls |= bl->brkcls;
436} 447}
437 448
438 449
@@ -441,6 +452,8 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
441 bl->nactvar = fs->nactvar; 452 bl->nactvar = fs->nactvar;
442 bl->firstlabel = fs->ls->dyd->label.n; 453 bl->firstlabel = fs->ls->dyd->label.n;
443 bl->firstgoto = fs->ls->dyd->gt.n; 454 bl->firstgoto = fs->ls->dyd->gt.n;
455 bl->brks = NO_JUMP;
456 bl->brkcls = 0;
444 bl->upval = 0; 457 bl->upval = 0;
445 bl->previous = fs->bl; 458 bl->previous = fs->bl;
446 fs->bl = bl; 459 fs->bl = bl;
@@ -449,22 +462,24 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
449 462
450 463
451/* 464/*
452** create a label named 'break' to resolve break statements 465** Fix all breaks in block 'bl' to jump to the end of the block.
453*/ 466*/
454static void breaklabel (LexState *ls) { 467static void fixbreaks (FuncState *fs, BlockCnt *bl) {
455 TString *n = luaS_new(ls->L, "break"); 468 int target = fs->pc;
456 int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); 469 if (bl->brkcls) /* does the block need to close upvalues? */
457 findgotos(ls, &ls->dyd->label.arr[l]); 470 luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
471 luaK_patchgoto(fs, bl->brks, target, bl->brkcls);
472 bl->brks = NO_JUMP; /* no more breaks to fix */
473 bl->brkcls = 0; /* no more need to close upvalues */
474 lua_assert(!bl->upval); /* loop body cannot have local variables */
458} 475}
459 476
477
460/* 478/*
461** generates an error for an undefined 'goto'; choose appropriate 479** generates an error for an undefined 'goto'.
462** message when label name is a reserved word (which can only be 'break')
463*/ 480*/
464static l_noret undefgoto (LexState *ls, Labeldesc *gt) { 481static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
465 const char *msg = isreserved(gt->name) 482 const char *msg = "no visible label '%s' for <goto> at line %d";
466 ? "<%s> at line %d not inside a loop"
467 : "no visible label '%s' for <goto> at line %d";
468 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); 483 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
469 semerror(ls, msg); 484 semerror(ls, msg);
470} 485}
@@ -473,14 +488,12 @@ static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
473static void leaveblock (FuncState *fs) { 488static void leaveblock (FuncState *fs) {
474 BlockCnt *bl = fs->bl; 489 BlockCnt *bl = fs->bl;
475 LexState *ls = fs->ls; 490 LexState *ls = fs->ls;
476 if (bl->previous && bl->upval) { 491 if (bl->upval && bl->brks != NO_JUMP) /* breaks in upvalue scopes? */
477 /* create a 'jump to here' to close upvalues */ 492 bl->brkcls = 1; /* these breaks must close the upvalues */
478 int j = luaK_jump(fs);
479 luaK_patchclose(fs, j, bl->nactvar);
480 luaK_patchtohere(fs, j);
481 }
482 if (bl->isloop) 493 if (bl->isloop)
483 breaklabel(ls); /* close pending breaks */ 494 fixbreaks(fs, bl); /* fix pending breaks */
495 if (bl->previous && bl->upval)
496 luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
484 fs->bl = bl->previous; 497 fs->bl = bl->previous;
485 removevars(fs, bl->nactvar); 498 removevars(fs, bl->nactvar);
486 lua_assert(bl->nactvar == fs->nactvar); 499 lua_assert(bl->nactvar == fs->nactvar);
@@ -488,8 +501,11 @@ static void leaveblock (FuncState *fs) {
488 ls->dyd->label.n = bl->firstlabel; /* remove local labels */ 501 ls->dyd->label.n = bl->firstlabel; /* remove local labels */
489 if (bl->previous) /* inner block? */ 502 if (bl->previous) /* inner block? */
490 movegotosout(fs, bl); /* update pending gotos to outer block */ 503 movegotosout(fs, bl); /* update pending gotos to outer block */
491 else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ 504 else {
492 undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ 505 lua_assert(bl->brks == NO_JUMP); /* no pending breaks */
506 if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
507 undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
508 }
493} 509}
494 510
495 511
@@ -1205,16 +1221,21 @@ static int cond (LexState *ls) {
1205 1221
1206static void gotostat (LexState *ls, int pc) { 1222static void gotostat (LexState *ls, int pc) {
1207 int line = ls->linenumber; 1223 int line = ls->linenumber;
1208 TString *label;
1209 int g; 1224 int g;
1210 if (testnext(ls, TK_GOTO)) 1225 luaX_next(ls); /* skip 'goto' */
1211 label = str_checkname(ls); 1226 g = newlabelentry(ls, &ls->dyd->gt, str_checkname(ls), line, pc);
1212 else { 1227 solvelabel(ls, g); /* close it if label already defined */
1213 luaX_next(ls); /* skip break */ 1228}
1214 label = luaS_new(ls->L, "break"); 1229
1215 } 1230
1216 g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); 1231static void breakstat (LexState *ls, int pc) {
1217 findlabel(ls, g); /* close it if label already defined */ 1232 FuncState *fs = ls->fs;
1233 BlockCnt *bl = fs->bl;
1234 luaX_next(ls); /* skip break */
1235 while (bl && !bl->isloop) { bl = bl->previous; }
1236 if (!bl)
1237 luaX_syntaxerror(ls, "no loop to break");
1238 luaK_concat(fs, &fs->bl->brks, pc);
1218} 1239}
1219 1240
1220 1241
@@ -1248,12 +1269,13 @@ static void labelstat (LexState *ls, TString *label, int line) {
1248 checknext(ls, TK_DBCOLON); /* skip double colon */ 1269 checknext(ls, TK_DBCOLON); /* skip double colon */
1249 /* create new entry for this label */ 1270 /* create new entry for this label */
1250 l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); 1271 l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
1272 luaK_codeABC(fs, OP_CLOSE, fs->nactvar, 0, 0);
1251 skipnoopstat(ls); /* skip other no-op statements */ 1273 skipnoopstat(ls); /* skip other no-op statements */
1252 if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ 1274 if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
1253 /* assume that locals are already out of scope */ 1275 /* assume that locals are already out of scope */
1254 ll->arr[l].nactvar = fs->bl->nactvar; 1276 ll->arr[l].nactvar = fs->bl->nactvar;
1255 } 1277 }
1256 findgotos(ls, &ll->arr[l]); 1278 solvegotos(ls, &ll->arr[l]);
1257} 1279}
1258 1280
1259 1281
@@ -1289,8 +1311,15 @@ static void repeatstat (LexState *ls, int line) {
1289 check_match(ls, TK_UNTIL, TK_REPEAT, line); 1311 check_match(ls, TK_UNTIL, TK_REPEAT, line);
1290 condexit = cond(ls); /* read condition (inside scope block) */ 1312 condexit = cond(ls); /* read condition (inside scope block) */
1291 if (bl2.upval) /* upvalues? */ 1313 if (bl2.upval) /* upvalues? */
1292 luaK_patchclose(fs, condexit, bl2.nactvar); 1314 luaK_patchclose(fs, condexit);
1293 leaveblock(fs); /* finish scope */ 1315 leaveblock(fs); /* finish scope */
1316 if (bl2.upval) { /* upvalues? */
1317 int exit = luaK_jump(fs); /* normal exit must jump over fix */
1318 luaK_patchtohere(fs, condexit); /* repetition must close upvalues */
1319 luaK_codeABC(fs, OP_CLOSE, bl2.nactvar, 0, 0);
1320 condexit = luaK_jump(fs); /* repeat after closing upvalues */
1321 luaK_patchtohere(fs, exit); /* normal exit comes to here */
1322 }
1294 luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ 1323 luaK_patchlist(fs, condexit, repeat_init); /* close the loop */
1295 leaveblock(fs); /* finish loop */ 1324 leaveblock(fs); /* finish loop */
1296} 1325}
@@ -1428,9 +1457,12 @@ static void test_then_block (LexState *ls, int *escapelist) {
1428 if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { 1457 if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) {
1429 luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ 1458 luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
1430 enterblock(fs, &bl, 0); /* must enter block before 'goto' */ 1459 enterblock(fs, &bl, 0); /* must enter block before 'goto' */
1431 gotostat(ls, v.t); /* handle goto/break */ 1460 if (ls->t.token == TK_GOTO)
1461 gotostat(ls, v.t); /* handle goto */
1462 else
1463 breakstat(ls, v.t); /* handle break */
1432 while (testnext(ls, ';')) {} /* skip semicolons */ 1464 while (testnext(ls, ';')) {} /* skip semicolons */
1433 if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ 1465 if (block_follow(ls, 0)) { /* 'goto'/'break' is the entire block? */
1434 leaveblock(fs); 1466 leaveblock(fs);
1435 return; /* and that is it */ 1467 return; /* and that is it */
1436 } 1468 }
@@ -1623,7 +1655,10 @@ static void statement (LexState *ls) {
1623 retstat(ls); 1655 retstat(ls);
1624 break; 1656 break;
1625 } 1657 }
1626 case TK_BREAK: /* stat -> breakstat */ 1658 case TK_BREAK: { /* stat -> breakstat */
1659 breakstat(ls, luaK_jump(ls->fs));
1660 break;
1661 }
1627 case TK_GOTO: { /* stat -> 'goto' NAME */ 1662 case TK_GOTO: { /* stat -> 'goto' NAME */
1628 gotostat(ls, luaK_jump(ls->fs)); 1663 gotostat(ls, luaK_jump(ls->fs));
1629 break; 1664 break;
diff --git a/lvm.c b/lvm.c
index be4793d1..b1e74f3d 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 2.290 2017/07/07 16:34:32 roberto Exp roberto $ 2** $Id: lvm.c,v 2.291 2017/08/14 18:33:14 roberto Exp roberto $
3** Lua virtual machine 3** Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -753,10 +753,7 @@ void luaV_finishOp (lua_State *L) {
753** Execute a jump instruction. The 'updatemask' allows signals to stop 753** Execute a jump instruction. The 'updatemask' allows signals to stop
754** tight loops. (Without it, the local copy of 'mask' could never change.) 754** tight loops. (Without it, the local copy of 'mask' could never change.)
755*/ 755*/
756#define dojump(ci,i,e) \ 756#define dojump(ci,i,e) { pc += GETARG_sBx(i) + e; updatemask(L); }
757 { int a = GETARG_A(i); \
758 if (a != 0) luaF_close(L, ci->func + a); \
759 pc += GETARG_sBx(i) + e; updatemask(L); }
760 757
761 758
762/* for test instructions, execute the jump instruction that follows it */ 759/* for test instructions, execute the jump instruction that follows it */
@@ -1201,6 +1198,10 @@ void luaV_execute (lua_State *L) {
1201 L->top = ci->top; /* restore top */ 1198 L->top = ci->top; /* restore top */
1202 vmbreak; 1199 vmbreak;
1203 } 1200 }
1201 vmcase(OP_CLOSE) {
1202 luaF_close(L, ra);
1203 vmbreak;
1204 }
1204 vmcase(OP_JMP) { 1205 vmcase(OP_JMP) {
1205 dojump(ci, i, 0); 1206 dojump(ci, i, 0);
1206 vmbreak; 1207 vmbreak;