static void leaveblock(FuncState *fs) { BlockCnt *bl = fs->bl; LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = luaK_jump(fs); luaK_patchclose(fs, j, bl->nactvar); luaK_patchtohere(fs, j); } if (bl->isloop) breaklabel(ls); /* close pending breaks */ fs->bl = bl->previous; removevars(fs, bl->nactvar); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(fs, bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ }
/* ** export pending gotos to outer level, to check them against ** outer labels; if the block being exited has upvalues, and ** the goto exits the scope of any variable (which can be the ** upvalue), close those variables being exited. */ static void movegotosout (FuncState *fs, BlockCnt *bl) { int i = bl->firstgoto; Labellist *gl = &fs->ls->dyd->gt; /* correct pending gotos to current block and try to close it with visible labels */ while (i < gl->n) { Labeldesc *gt = &gl->arr[i]; if (gt->nactvar > bl->nactvar) { if (bl->upval) luaK_patchclose(fs, gt->pc, bl->nactvar); gt->nactvar = bl->nactvar; } if (!findlabel(fs->ls, i)) i++; /* move to next one */ } }
/* ** try to close a goto with existing labels; this solves backward jumps */ static int findlabel (LexState *ls, int g) { int i; BlockCnt *bl = ls->fs->bl; Dyndata *dyd = ls->dyd; Labeldesc *gt = &dyd->gt.arr[g]; /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; if (eqstr(lb->name, gt->name)) { /* correct label? */ if (gt->nactvar > lb->nactvar && (bl->upval || dyd->label.n > bl->firstlabel)) luaK_patchclose(ls->fs, gt->pc, lb->nactvar); closegoto(ls, g, lb); /* close it */ return 1; } } return 0; /* label not found; cannot close goto */ }
/*static*/ void FuncState::leaveblock (/*FuncState *fs*/) { //BlockCnt *bl = fs->bl; //LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = luaK_jump(); luaK_patchclose(j, bl->nactvar); luaK_patchtohere(j); } if (bl->isloop) ls->breaklabel(); /* close pending breaks */ bl = bl->previous; removevars(bl->nactvar); lua_assert(bl->nactvar == nactvar); free_reg = nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ ls->undefgoto(&ls->dyd->gt.arr[bl->firstgoto]); /* error */ }