diff options
author | Mike Pall <mike> | 2012-09-16 18:46:04 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2012-09-16 18:46:04 +0200 |
commit | ead325b0c9deafb23f499f9739acca3bb36c3e46 (patch) | |
tree | ba120a3bb3c5fb2d8b4cf30ab5341d619cba52f3 | |
parent | aed20093781541c19b5c7d6149eda71a7141bc1c (diff) | |
download | luajit-ead325b0c9deafb23f499f9739acca3bb36c3e46.tar.gz luajit-ead325b0c9deafb23f499f9739acca3bb36c3e46.tar.bz2 luajit-ead325b0c9deafb23f499f9739acca3bb36c3e46.zip |
From Lua 5.2: Add goto and ::label:: statements.
-rw-r--r-- | src/lj_errmsg.h | 5 | ||||
-rw-r--r-- | src/lj_lex.c | 5 | ||||
-rw-r--r-- | src/lj_lex.h | 5 | ||||
-rw-r--r-- | src/lj_parse.c | 517 | ||||
-rw-r--r-- | src/lj_record.c | 2 |
5 files changed, 362 insertions, 172 deletions
diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h index dd3eefa8..c07d4387 100644 --- a/src/lj_errmsg.h +++ b/src/lj_errmsg.h | |||
@@ -134,8 +134,11 @@ ERRDEF(XFUNARG, "function arguments expected") | |||
134 | ERRDEF(XSYMBOL, "unexpected symbol") | 134 | ERRDEF(XSYMBOL, "unexpected symbol") |
135 | ERRDEF(XDOTS, "cannot use " LUA_QL("...") " outside a vararg function") | 135 | ERRDEF(XDOTS, "cannot use " LUA_QL("...") " outside a vararg function") |
136 | ERRDEF(XSYNTAX, "syntax error") | 136 | ERRDEF(XSYNTAX, "syntax error") |
137 | ERRDEF(XBREAK, "no loop to break") | ||
138 | ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") | 137 | ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") |
138 | ERRDEF(XBREAK, "no loop to break") | ||
139 | ERRDEF(XLUNDEF, "undefined label " LUA_QS) | ||
140 | ERRDEF(XLDUP, "duplicate label " LUA_QS) | ||
141 | ERRDEF(XGSCOPE, "<goto %s> jumps into the scope of local " LUA_QS) | ||
139 | 142 | ||
140 | /* Bytecode reader errors. */ | 143 | /* Bytecode reader errors. */ |
141 | ERRDEF(BCFMT, "cannot load incompatible bytecode") | 144 | ERRDEF(BCFMT, "cannot load incompatible bytecode") |
diff --git a/src/lj_lex.c b/src/lj_lex.c index c85ea314..e464f420 100644 --- a/src/lj_lex.c +++ b/src/lj_lex.c | |||
@@ -272,9 +272,9 @@ static int llex(LexState *ls, TValue *tv) | |||
272 | save_and_next(ls); | 272 | save_and_next(ls); |
273 | } while (lj_char_isident(ls->current)); | 273 | } while (lj_char_isident(ls->current)); |
274 | s = lj_parse_keepstr(ls, ls->sb.buf, ls->sb.n); | 274 | s = lj_parse_keepstr(ls, ls->sb.buf, ls->sb.n); |
275 | setstrV(ls->L, tv, s); | ||
275 | if (s->reserved > 0) /* Reserved word? */ | 276 | if (s->reserved > 0) /* Reserved word? */ |
276 | return TK_OFS + s->reserved; | 277 | return TK_OFS + s->reserved; |
277 | setstrV(ls->L, tv, s); | ||
278 | return TK_name; | 278 | return TK_name; |
279 | } | 279 | } |
280 | switch (ls->current) { | 280 | switch (ls->current) { |
@@ -330,6 +330,9 @@ static int llex(LexState *ls, TValue *tv) | |||
330 | case '~': | 330 | case '~': |
331 | next(ls); | 331 | next(ls); |
332 | if (ls->current != '=') return '~'; else { next(ls); return TK_ne; } | 332 | if (ls->current != '=') return '~'; else { next(ls); return TK_ne; } |
333 | case ':': | ||
334 | next(ls); | ||
335 | if (ls->current != ':') return ':'; else { next(ls); return TK_label; } | ||
333 | case '"': | 336 | case '"': |
334 | case '\'': | 337 | case '\'': |
335 | read_string(ls, ls->current, tv); | 338 | read_string(ls, ls->current, tv); |
diff --git a/src/lj_lex.h b/src/lj_lex.h index 1ddf4b59..16f35aa5 100644 --- a/src/lj_lex.h +++ b/src/lj_lex.h | |||
@@ -15,10 +15,11 @@ | |||
15 | /* Lua lexer tokens. */ | 15 | /* Lua lexer tokens. */ |
16 | #define TKDEF(_, __) \ | 16 | #define TKDEF(_, __) \ |
17 | _(and) _(break) _(do) _(else) _(elseif) _(end) _(false) \ | 17 | _(and) _(break) _(do) _(else) _(elseif) _(end) _(false) \ |
18 | _(for) _(function) _(if) _(in) _(local) _(nil) _(not) _(or) \ | 18 | _(for) _(function) _(goto) _(if) _(in) _(local) _(nil) _(not) _(or) \ |
19 | _(repeat) _(return) _(then) _(true) _(until) _(while) \ | 19 | _(repeat) _(return) _(then) _(true) _(until) _(while) \ |
20 | __(concat, ..) __(dots, ...) __(eq, ==) __(ge, >=) __(le, <=) __(ne, ~=) \ | 20 | __(concat, ..) __(dots, ...) __(eq, ==) __(ge, >=) __(le, <=) __(ne, ~=) \ |
21 | __(number, <number>) __(name, <name>) __(string, <string>) __(eof, <eof>) | 21 | __(label, ::) __(number, <number>) __(name, <name>) __(string, <string>) \ |
22 | __(eof, <eof>) | ||
22 | 23 | ||
23 | enum { | 24 | enum { |
24 | TK_OFS = 256, | 25 | TK_OFS = 256, |
diff --git a/src/lj_parse.c b/src/lj_parse.c index 6c2f0d31..322a542d 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c | |||
@@ -95,17 +95,28 @@ static int expr_numiszero(ExpDesc *e) | |||
95 | /* Per-function linked list of scope blocks. */ | 95 | /* Per-function linked list of scope blocks. */ |
96 | typedef struct FuncScope { | 96 | typedef struct FuncScope { |
97 | struct FuncScope *prev; /* Link to outer scope. */ | 97 | struct FuncScope *prev; /* Link to outer scope. */ |
98 | BCPos breaklist; /* Jump list for loop breaks. */ | 98 | MSize vstart; /* Start of block-local variables. */ |
99 | uint8_t nactvar; /* Number of active vars outside the scope. */ | 99 | uint8_t nactvar; /* Number of active vars outside the scope. */ |
100 | uint8_t upval; /* Some variable in the scope is an upvalue. */ | 100 | uint8_t flags; /* Scope flags. */ |
101 | uint8_t isbreakable; /* Scope is a loop and allows a break. */ | ||
102 | } FuncScope; | 101 | } FuncScope; |
103 | 102 | ||
103 | #define FSCOPE_LOOP 0x01 /* Scope is a (breakable) loop. */ | ||
104 | #define FSCOPE_BREAK 0x02 /* Break used in scope. */ | ||
105 | #define FSCOPE_GOLA 0x04 /* Goto or label used in scope. */ | ||
106 | #define FSCOPE_UPVAL 0x08 /* Upvalue in scope. */ | ||
107 | #define FSCOPE_NOCLOSE 0x10 /* Do not close upvalues. */ | ||
108 | |||
109 | #define NAME_BREAK ((GCstr *)(uintptr_t)1) | ||
110 | |||
104 | /* Index into variable stack. */ | 111 | /* Index into variable stack. */ |
105 | typedef uint16_t VarIndex; | 112 | typedef uint16_t VarIndex; |
106 | #define LJ_MAX_VSTACK 65536 | 113 | #define LJ_MAX_VSTACK 65536 |
107 | 114 | ||
108 | #define VSTACK_VAR_RW 0x80000000 /* In endpc: R/W variable. */ | 115 | /* Flags stored in upper bits of endpc. */ |
116 | #define VSTACK_MASK 0x1fffffff /* Mask for actual endpc. */ | ||
117 | #define VSTACK_VAR_RW 0x80000000 /* R/W variable. */ | ||
118 | #define VSTACK_GOTO 0x40000000 /* Pending goto. */ | ||
119 | #define VSTACK_LABEL 0x20000000 /* Label. */ | ||
109 | 120 | ||
110 | /* Upvalue map. */ | 121 | /* Upvalue map. */ |
111 | typedef struct UVMap { | 122 | typedef struct UVMap { |
@@ -680,8 +691,7 @@ static BCPos bcemit_jmp(FuncState *fs) | |||
680 | BCPos j = fs->pc - 1; | 691 | BCPos j = fs->pc - 1; |
681 | BCIns *ip = &fs->bcbase[j].ins; | 692 | BCIns *ip = &fs->bcbase[j].ins; |
682 | fs->jpc = NO_JMP; | 693 | fs->jpc = NO_JMP; |
683 | if ((int32_t)j >= (int32_t)fs->lasttarget && | 694 | if ((int32_t)j >= (int32_t)fs->lasttarget && bc_op(*ip) == BC_UCLO) |
684 | bc_op(*ip) == BC_UCLO) | ||
685 | setbc_j(ip, NO_JMP); | 695 | setbc_j(ip, NO_JMP); |
686 | else | 696 | else |
687 | j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP); | 697 | j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP); |
@@ -1009,7 +1019,7 @@ static void lex_match(LexState *ls, LexToken what, LexToken who, BCLine line) | |||
1009 | static GCstr *lex_str(LexState *ls) | 1019 | static GCstr *lex_str(LexState *ls) |
1010 | { | 1020 | { |
1011 | GCstr *s; | 1021 | GCstr *s; |
1012 | if (ls->token != TK_name) | 1022 | if (ls->token != TK_name && (LJ_52 || ls->token != TK_goto)) |
1013 | err_token(ls, TK_name); | 1023 | err_token(ls, TK_name); |
1014 | s = strV(&ls->tokenval); | 1024 | s = strV(&ls->tokenval); |
1015 | lj_lex_next(ls); | 1025 | lj_lex_next(ls); |
@@ -1094,7 +1104,7 @@ static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e) | |||
1094 | } | 1104 | } |
1095 | 1105 | ||
1096 | /* Forward declaration. */ | 1106 | /* Forward declaration. */ |
1097 | static void scope_uvmark(FuncState *fs, BCReg level); | 1107 | static void fscope_uvmark(FuncState *fs, BCReg level); |
1098 | 1108 | ||
1099 | /* Recursively lookup variables in enclosing functions. */ | 1109 | /* Recursively lookup variables in enclosing functions. */ |
1100 | static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) | 1110 | static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) |
@@ -1104,7 +1114,7 @@ static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) | |||
1104 | if ((int32_t)reg >= 0) { /* Local in this function? */ | 1114 | if ((int32_t)reg >= 0) { /* Local in this function? */ |
1105 | expr_init(e, VLOCAL, reg); | 1115 | expr_init(e, VLOCAL, reg); |
1106 | if (!first) | 1116 | if (!first) |
1107 | scope_uvmark(fs, reg); /* Scope now has an upvalue. */ | 1117 | fscope_uvmark(fs, reg); /* Scope now has an upvalue. */ |
1108 | return (MSize)(e->u.s.aux = (uint32_t)fs->varmap[reg]); | 1118 | return (MSize)(e->u.s.aux = (uint32_t)fs->varmap[reg]); |
1109 | } else { | 1119 | } else { |
1110 | MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */ | 1120 | MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */ |
@@ -1125,6 +1135,170 @@ static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) | |||
1125 | #define var_lookup(ls, e) \ | 1135 | #define var_lookup(ls, e) \ |
1126 | var_lookup_((ls)->fs, lex_str(ls), (e), 1) | 1136 | var_lookup_((ls)->fs, lex_str(ls), (e), 1) |
1127 | 1137 | ||
1138 | /* -- Goto an label handling ---------------------------------------------- */ | ||
1139 | |||
1140 | /* Add a new goto or label. */ | ||
1141 | static MSize gola_new(LexState *ls, GCstr *name, uint32_t type, BCPos pc) | ||
1142 | { | ||
1143 | FuncState *fs = ls->fs; | ||
1144 | MSize vtop = ls->vtop; | ||
1145 | if (LJ_UNLIKELY(vtop >= ls->sizevstack)) { | ||
1146 | if (ls->sizevstack >= LJ_MAX_VSTACK) | ||
1147 | lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK); | ||
1148 | lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo); | ||
1149 | } | ||
1150 | lua_assert(name == NAME_BREAK || lj_tab_getstr(fs->kt, name) != NULL); | ||
1151 | /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ | ||
1152 | setgcref(ls->vstack[vtop].name, obj2gco(name)); | ||
1153 | ls->vstack[vtop].startpc = pc; | ||
1154 | ls->vstack[vtop].endpc = fs->nactvar | type; | ||
1155 | ls->vtop = vtop+1; | ||
1156 | return vtop; | ||
1157 | } | ||
1158 | |||
1159 | #define gola_nactvar(v) ((uint8_t)((v)->endpc)) | ||
1160 | #define gola_isgoto(v) ((v)->endpc & VSTACK_GOTO) | ||
1161 | #define gola_islabel(v) ((v)->endpc & VSTACK_LABEL) | ||
1162 | #define gola_isgotolabel(v) ((v)->endpc & (VSTACK_GOTO|VSTACK_LABEL)) | ||
1163 | |||
1164 | /* Patch goto to jump to label. */ | ||
1165 | static void gola_patch(LexState *ls, VarInfo *vg, VarInfo *vl) | ||
1166 | { | ||
1167 | FuncState *fs = ls->fs; | ||
1168 | BCPos pc = vg->startpc; | ||
1169 | setgcrefnull(vg->name); /* Invalidate pending goto. */ | ||
1170 | setbc_a(&fs->bcbase[pc].ins, gola_nactvar(vl)); | ||
1171 | jmp_patch(fs, pc, vl->startpc); | ||
1172 | } | ||
1173 | |||
1174 | /* Patch goto to close upvalues. */ | ||
1175 | static void gola_close(LexState *ls, VarInfo *vg) | ||
1176 | { | ||
1177 | FuncState *fs = ls->fs; | ||
1178 | BCPos pc = vg->startpc; | ||
1179 | BCIns *ip = &fs->bcbase[pc].ins; | ||
1180 | lua_assert(gola_isgoto(vg)); | ||
1181 | lua_assert(bc_op(*ip) == BC_JMP || bc_op(*ip) == BC_UCLO); | ||
1182 | setbc_a(ip, gola_nactvar(vg)); | ||
1183 | if (bc_op(*ip) == BC_JMP) { | ||
1184 | BCPos next = jmp_next(fs, pc); | ||
1185 | if (next != NO_JMP) jmp_patch(fs, next, pc); /* Jump to UCLO. */ | ||
1186 | setbc_op(ip, BC_UCLO); /* Turn into UCLO. */ | ||
1187 | setbc_j(ip, NO_JMP); | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | /* Resolve pending forward gotos for label. */ | ||
1192 | static void gola_resolve(LexState *ls, MSize idx) | ||
1193 | { | ||
1194 | VarInfo *vg = ls->vstack + ls->fs->bl->vstart; | ||
1195 | VarInfo *vl = ls->vstack + idx; | ||
1196 | for (; vg < vl; vg++) | ||
1197 | if (gcrefeq(vg->name, vl->name) && gola_isgoto(vg)) { | ||
1198 | if (gola_nactvar(vg) < gola_nactvar(vl)) { | ||
1199 | GCstr *name = strref(var_get(ls, ls->fs, gola_nactvar(vg)).name); | ||
1200 | lua_assert((uintptr_t)name >= VARNAME__MAX); | ||
1201 | ls->linenumber = ls->fs->bcbase[vg->startpc].line; | ||
1202 | lj_lex_error(ls, 0, LJ_ERR_XGSCOPE, | ||
1203 | strdata(strref(vg->name)), strdata(name)); | ||
1204 | } | ||
1205 | gola_patch(ls, vg, vl); | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | /* Fixup remaining gotos and labels for scope. */ | ||
1210 | static void gola_fixup(LexState *ls, FuncScope *bl) | ||
1211 | { | ||
1212 | VarInfo *v = ls->vstack + bl->vstart; | ||
1213 | VarInfo *ve = ls->vstack + ls->vtop; | ||
1214 | for (; v < ve; v++) { | ||
1215 | GCstr *name = strref(v->name); | ||
1216 | if (name != NULL) { /* Only consider remaining valid gotos/labels. */ | ||
1217 | if (gola_islabel(v)) { | ||
1218 | VarInfo *vg; | ||
1219 | setgcrefnull(v->name); /* Invalidate label that goes out of scope. */ | ||
1220 | for (vg = v+1; vg < ve; vg++) /* Resolve pending backward gotos. */ | ||
1221 | if (strref(vg->name) == name && gola_isgoto(vg)) { | ||
1222 | if ((bl->flags&FSCOPE_UPVAL) && gola_nactvar(vg) > gola_nactvar(v)) | ||
1223 | gola_close(ls, vg); | ||
1224 | gola_patch(ls, vg, v); | ||
1225 | } | ||
1226 | } else if (gola_isgoto(v)) { | ||
1227 | if (bl->prev) { /* Propagate goto or break to outer scope. */ | ||
1228 | bl->prev->flags |= name == NAME_BREAK ? FSCOPE_BREAK : FSCOPE_GOLA; | ||
1229 | v->endpc = bl->nactvar | VSTACK_GOTO; | ||
1230 | if ((bl->flags & FSCOPE_UPVAL)) | ||
1231 | gola_close(ls, v); | ||
1232 | } else { /* No outer scope: undefined goto label or no loop. */ | ||
1233 | ls->linenumber = ls->fs->bcbase[v->startpc].line; | ||
1234 | if (name == NAME_BREAK) | ||
1235 | lj_lex_error(ls, 0, LJ_ERR_XBREAK); | ||
1236 | else | ||
1237 | lj_lex_error(ls, 0, LJ_ERR_XLUNDEF, strdata(name)); | ||
1238 | } | ||
1239 | } | ||
1240 | } | ||
1241 | } | ||
1242 | } | ||
1243 | |||
1244 | /* Find existing label. */ | ||
1245 | static VarInfo *gola_findlabel(LexState *ls, GCstr *name) | ||
1246 | { | ||
1247 | VarInfo *v = ls->vstack + ls->fs->bl->vstart; | ||
1248 | VarInfo *ve = ls->vstack + ls->vtop; | ||
1249 | for (; v < ve; v++) | ||
1250 | if (strref(v->name) == name && gola_islabel(v)) | ||
1251 | return v; | ||
1252 | return NULL; | ||
1253 | } | ||
1254 | |||
1255 | /* -- Scope handling ------------------------------------------------------ */ | ||
1256 | |||
1257 | /* Begin a scope. */ | ||
1258 | static void fscope_begin(FuncState *fs, FuncScope *bl, int flags) | ||
1259 | { | ||
1260 | bl->nactvar = (uint8_t)fs->nactvar; | ||
1261 | bl->flags = flags; | ||
1262 | bl->vstart = fs->ls->vtop; | ||
1263 | bl->prev = fs->bl; | ||
1264 | fs->bl = bl; | ||
1265 | lua_assert(fs->freereg == fs->nactvar); | ||
1266 | } | ||
1267 | |||
1268 | /* End a scope. */ | ||
1269 | static void fscope_end(FuncState *fs) | ||
1270 | { | ||
1271 | FuncScope *bl = fs->bl; | ||
1272 | LexState *ls = fs->ls; | ||
1273 | fs->bl = bl->prev; | ||
1274 | var_remove(ls, bl->nactvar); | ||
1275 | fs->freereg = fs->nactvar; | ||
1276 | lua_assert(bl->nactvar == fs->nactvar); | ||
1277 | if ((bl->flags & (FSCOPE_UPVAL|FSCOPE_NOCLOSE)) == FSCOPE_UPVAL) | ||
1278 | bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); | ||
1279 | if ((bl->flags & FSCOPE_BREAK)) { | ||
1280 | if ((bl->flags & FSCOPE_LOOP)) { | ||
1281 | MSize idx = gola_new(ls, NAME_BREAK, VSTACK_LABEL, fs->pc); | ||
1282 | ls->vtop = idx; /* Drop break label immediately. */ | ||
1283 | gola_resolve(ls, idx); | ||
1284 | return; | ||
1285 | } /* else: need the fixup step to propagate the breaks. */ | ||
1286 | } else if (!(bl->flags & FSCOPE_GOLA)) { | ||
1287 | return; | ||
1288 | } | ||
1289 | gola_fixup(ls, bl); | ||
1290 | } | ||
1291 | |||
1292 | /* Mark scope as having an upvalue. */ | ||
1293 | static void fscope_uvmark(FuncState *fs, BCReg level) | ||
1294 | { | ||
1295 | FuncScope *bl; | ||
1296 | for (bl = fs->bl; bl && bl->nactvar > level; bl = bl->prev) | ||
1297 | ; | ||
1298 | if (bl) | ||
1299 | bl->flags |= FSCOPE_UPVAL; | ||
1300 | } | ||
1301 | |||
1128 | /* -- Function state management ------------------------------------------- */ | 1302 | /* -- Function state management ------------------------------------------- */ |
1129 | 1303 | ||
1130 | /* Fixup bytecode for prototype. */ | 1304 | /* Fixup bytecode for prototype. */ |
@@ -1287,36 +1461,37 @@ static void fs_buf_uleb128(LexState *ls, uint32_t v) | |||
1287 | /* Prepare variable info for prototype. */ | 1461 | /* Prepare variable info for prototype. */ |
1288 | static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar) | 1462 | static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar) |
1289 | { | 1463 | { |
1290 | VarInfo *vstack = fs->ls->vstack; | 1464 | VarInfo *vs = fs->ls->vstack, *ve; |
1291 | MSize i, n; | 1465 | MSize i, n; |
1292 | BCPos lastpc; | 1466 | BCPos lastpc; |
1293 | lj_str_resetbuf(&ls->sb); /* Copy to temp. string buffer. */ | 1467 | lj_str_resetbuf(&ls->sb); /* Copy to temp. string buffer. */ |
1294 | /* Store upvalue names. */ | 1468 | /* Store upvalue names. */ |
1295 | for (i = 0, n = fs->nuv; i < n; i++) { | 1469 | for (i = 0, n = fs->nuv; i < n; i++) { |
1296 | GCstr *s = strref(vstack[fs->uvloc[i].vidx].name); | 1470 | GCstr *s = strref(vs[fs->uvloc[i].vidx].name); |
1297 | MSize len = s->len+1; | 1471 | MSize len = s->len+1; |
1298 | fs_buf_need(ls, len); | 1472 | fs_buf_need(ls, len); |
1299 | fs_buf_str(ls, strdata(s), len); | 1473 | fs_buf_str(ls, strdata(s), len); |
1300 | } | 1474 | } |
1301 | *ofsvar = ls->sb.n; | 1475 | *ofsvar = ls->sb.n; |
1302 | vstack += fs->vbase; | ||
1303 | lastpc = 0; | 1476 | lastpc = 0; |
1304 | /* Store local variable names and compressed ranges. */ | 1477 | /* Store local variable names and compressed ranges. */ |
1305 | for (i = 0, n = ls->vtop - fs->vbase; i < n; i++) { | 1478 | for (ve = vs + ls->vtop, vs += fs->vbase; vs < ve; vs++) { |
1306 | GCstr *s = strref(vstack[i].name); | 1479 | if (!gola_isgotolabel(vs)) { |
1307 | BCPos startpc = vstack[i].startpc; | 1480 | GCstr *s = strref(vs->name); |
1308 | BCPos endpc = vstack[i].endpc & ~VSTACK_VAR_RW; | 1481 | BCPos startpc; |
1309 | if ((uintptr_t)s < VARNAME__MAX) { | 1482 | if ((uintptr_t)s < VARNAME__MAX) { |
1310 | fs_buf_need(ls, 1 + 2*5); | 1483 | fs_buf_need(ls, 1 + 2*5); |
1311 | ls->sb.buf[ls->sb.n++] = (uint8_t)(uintptr_t)s; | 1484 | ls->sb.buf[ls->sb.n++] = (uint8_t)(uintptr_t)s; |
1312 | } else { | 1485 | } else { |
1313 | MSize len = s->len+1; | 1486 | MSize len = s->len+1; |
1314 | fs_buf_need(ls, len + 2*5); | 1487 | fs_buf_need(ls, len + 2*5); |
1315 | fs_buf_str(ls, strdata(s), len); | 1488 | fs_buf_str(ls, strdata(s), len); |
1489 | } | ||
1490 | startpc = vs->startpc; | ||
1491 | fs_buf_uleb128(ls, startpc-lastpc); | ||
1492 | fs_buf_uleb128(ls, (vs->endpc & VSTACK_MASK)-startpc); | ||
1493 | lastpc = startpc; | ||
1316 | } | 1494 | } |
1317 | fs_buf_uleb128(ls, startpc-lastpc); | ||
1318 | fs_buf_uleb128(ls, endpc-startpc); | ||
1319 | lastpc = startpc; | ||
1320 | } | 1495 | } |
1321 | fs_buf_need(ls, 1); | 1496 | fs_buf_need(ls, 1); |
1322 | ls->sb.buf[ls->sb.n++] = '\0'; /* Terminator for varinfo. */ | 1497 | ls->sb.buf[ls->sb.n++] = '\0'; /* Terminator for varinfo. */ |
@@ -1359,14 +1534,17 @@ static void fs_fixup_ret(FuncState *fs) | |||
1359 | { | 1534 | { |
1360 | BCPos lastpc = fs->pc; | 1535 | BCPos lastpc = fs->pc; |
1361 | if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) { | 1536 | if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) { |
1362 | if (fs->flags & PROTO_CHILD) | 1537 | if ((fs->bl->flags & FSCOPE_UPVAL)) |
1363 | bcemit_AJ(fs, BC_UCLO, 0, 0); | 1538 | bcemit_AJ(fs, BC_UCLO, 0, 0); |
1364 | bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ | 1539 | bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ |
1365 | } | 1540 | } |
1541 | fs->bl->flags |= FSCOPE_NOCLOSE; /* Handled above. */ | ||
1542 | fscope_end(fs); | ||
1543 | lua_assert(fs->bl == NULL); | ||
1366 | /* May need to fixup returns encoded before first function was created. */ | 1544 | /* May need to fixup returns encoded before first function was created. */ |
1367 | if (fs->flags & PROTO_FIXUP_RETURN) { | 1545 | if (fs->flags & PROTO_FIXUP_RETURN) { |
1368 | BCPos pc; | 1546 | BCPos pc; |
1369 | for (pc = 0; pc < lastpc; pc++) { | 1547 | for (pc = 1; pc < lastpc; pc++) { |
1370 | BCIns ins = fs->bcbase[pc].ins; | 1548 | BCIns ins = fs->bcbase[pc].ins; |
1371 | BCPos offset; | 1549 | BCPos offset; |
1372 | switch (bc_op(ins)) { | 1550 | switch (bc_op(ins)) { |
@@ -1397,9 +1575,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
1397 | GCproto *pt; | 1575 | GCproto *pt; |
1398 | 1576 | ||
1399 | /* Apply final fixups. */ | 1577 | /* Apply final fixups. */ |
1400 | lua_assert(fs->bl == NULL); | ||
1401 | fs_fixup_ret(fs); | 1578 | fs_fixup_ret(fs); |
1402 | var_remove(ls, 0); | ||
1403 | 1579 | ||
1404 | /* Calculate total size of prototype including all colocated arrays. */ | 1580 | /* Calculate total size of prototype including all colocated arrays. */ |
1405 | sizept = sizeof(GCproto) + fs->pc*sizeof(BCIns) + fs->nkgc*sizeof(GCRef); | 1581 | sizept = sizeof(GCproto) + fs->pc*sizeof(BCIns) + fs->nkgc*sizeof(GCRef); |
@@ -1564,7 +1740,8 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
1564 | if (!expr_isk(&key)) expr_index(fs, e, &key); | 1740 | if (!expr_isk(&key)) expr_index(fs, e, &key); |
1565 | if (expr_isnumk(&key) && expr_numiszero(&key)) needarr = 1; else nhash++; | 1741 | if (expr_isnumk(&key) && expr_numiszero(&key)) needarr = 1; else nhash++; |
1566 | lex_check(ls, '='); | 1742 | lex_check(ls, '='); |
1567 | } else if (ls->token == TK_name && lj_lex_lookahead(ls) == '=') { | 1743 | } else if ((ls->token == TK_name || (!LJ_52 && ls->token == TK_goto)) && |
1744 | lj_lex_lookahead(ls) == '=') { | ||
1568 | expr_str(ls, &key); | 1745 | expr_str(ls, &key); |
1569 | lex_check(ls, '='); | 1746 | lex_check(ls, '='); |
1570 | nhash++; | 1747 | nhash++; |
@@ -1657,7 +1834,7 @@ static BCReg parse_params(LexState *ls, int needself) | |||
1657 | var_new_lit(ls, nparams++, "self"); | 1834 | var_new_lit(ls, nparams++, "self"); |
1658 | if (ls->token != ')') { | 1835 | if (ls->token != ')') { |
1659 | do { | 1836 | do { |
1660 | if (ls->token == TK_name) { | 1837 | if (ls->token == TK_name || (!LJ_52 && ls->token == TK_goto)) { |
1661 | var_new(ls, nparams++, lex_str(ls)); | 1838 | var_new(ls, nparams++, lex_str(ls)); |
1662 | } else if (ls->token == TK_dots) { | 1839 | } else if (ls->token == TK_dots) { |
1663 | lj_lex_next(ls); | 1840 | lj_lex_next(ls); |
@@ -1682,9 +1859,11 @@ static void parse_chunk(LexState *ls); | |||
1682 | static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) | 1859 | static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) |
1683 | { | 1860 | { |
1684 | FuncState fs, *pfs = ls->fs; | 1861 | FuncState fs, *pfs = ls->fs; |
1862 | FuncScope bl; | ||
1685 | GCproto *pt; | 1863 | GCproto *pt; |
1686 | ptrdiff_t oldbase = pfs->bcbase - ls->bcstack; | 1864 | ptrdiff_t oldbase = pfs->bcbase - ls->bcstack; |
1687 | fs_init(ls, &fs); | 1865 | fs_init(ls, &fs); |
1866 | fscope_begin(&fs, &bl, 0); | ||
1688 | fs.linedefined = line; | 1867 | fs.linedefined = line; |
1689 | fs.numparams = (uint8_t)parse_params(ls, needself); | 1868 | fs.numparams = (uint8_t)parse_params(ls, needself); |
1690 | fs.bcbase = pfs->bcbase + pfs->pc; | 1869 | fs.bcbase = pfs->bcbase + pfs->pc; |
@@ -1778,7 +1957,7 @@ static void expr_primary(LexState *ls, ExpDesc *v) | |||
1778 | expr(ls, v); | 1957 | expr(ls, v); |
1779 | lex_match(ls, ')', '(', line); | 1958 | lex_match(ls, ')', '(', line); |
1780 | expr_discharge(ls->fs, v); | 1959 | expr_discharge(ls->fs, v); |
1781 | } else if (ls->token == TK_name) { | 1960 | } else if (ls->token == TK_name || (!LJ_52 && ls->token == TK_goto)) { |
1782 | var_lookup(ls, v); | 1961 | var_lookup(ls, v); |
1783 | } else { | 1962 | } else { |
1784 | err_syntax(ls, LJ_ERR_XSYMBOL); | 1963 | err_syntax(ls, LJ_ERR_XSYMBOL); |
@@ -1964,125 +2143,6 @@ static BCPos expr_cond(LexState *ls) | |||
1964 | return v.f; | 2143 | return v.f; |
1965 | } | 2144 | } |
1966 | 2145 | ||
1967 | /* -- Scope handling ------------------------------------------------------ */ | ||
1968 | |||
1969 | /* Begin a scope. */ | ||
1970 | static void scope_begin(FuncState *fs, FuncScope *bl, int isbreakable) | ||
1971 | { | ||
1972 | bl->breaklist = NO_JMP; | ||
1973 | bl->isbreakable = (uint8_t)isbreakable; | ||
1974 | bl->nactvar = (uint8_t)fs->nactvar; | ||
1975 | bl->upval = 0; | ||
1976 | bl->prev = fs->bl; | ||
1977 | fs->bl = bl; | ||
1978 | lua_assert(fs->freereg == fs->nactvar); | ||
1979 | } | ||
1980 | |||
1981 | /* End a scope. */ | ||
1982 | static void scope_end(FuncState *fs) | ||
1983 | { | ||
1984 | FuncScope *bl = fs->bl; | ||
1985 | fs->bl = bl->prev; | ||
1986 | var_remove(fs->ls, bl->nactvar); | ||
1987 | fs->freereg = fs->nactvar; | ||
1988 | lua_assert(bl->nactvar == fs->nactvar); | ||
1989 | /* A scope is either breakable or has upvalues. */ | ||
1990 | lua_assert(!bl->isbreakable || !bl->upval); | ||
1991 | if (bl->upval) | ||
1992 | bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); | ||
1993 | else /* Avoid in upval case, it clears lasttarget and kills UCLO+JMP join. */ | ||
1994 | jmp_tohere(fs, bl->breaklist); | ||
1995 | } | ||
1996 | |||
1997 | /* Mark scope as having an upvalue. */ | ||
1998 | static void scope_uvmark(FuncState *fs, BCReg level) | ||
1999 | { | ||
2000 | FuncScope *bl; | ||
2001 | for (bl = fs->bl; bl && bl->nactvar > level; bl = bl->prev) | ||
2002 | ; | ||
2003 | if (bl) | ||
2004 | bl->upval = 1; | ||
2005 | } | ||
2006 | |||
2007 | /* Parse 'break' statement. */ | ||
2008 | static void parse_break(LexState *ls) | ||
2009 | { | ||
2010 | FuncState *fs = ls->fs; | ||
2011 | FuncScope *bl; | ||
2012 | BCReg savefr; | ||
2013 | int upval = 0; | ||
2014 | for (bl = fs->bl; bl && !bl->isbreakable; bl = bl->prev) | ||
2015 | upval |= bl->upval; /* Collect upvalues in intervening scopes. */ | ||
2016 | if (!bl) /* Error if no breakable scope found. */ | ||
2017 | err_syntax(ls, LJ_ERR_XBREAK); | ||
2018 | savefr = fs->freereg; | ||
2019 | fs->freereg = bl->nactvar; /* Shrink slots to help data-flow analysis. */ | ||
2020 | if (upval) | ||
2021 | bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); /* Close upvalues. */ | ||
2022 | jmp_append(fs, &bl->breaklist, bcemit_jmp(fs)); | ||
2023 | fs->freereg = savefr; | ||
2024 | } | ||
2025 | |||
2026 | /* Check for end of block. */ | ||
2027 | static int endofblock(LexToken token) | ||
2028 | { | ||
2029 | switch (token) { | ||
2030 | case TK_else: case TK_elseif: case TK_end: case TK_until: case TK_eof: | ||
2031 | return 1; | ||
2032 | default: | ||
2033 | return 0; | ||
2034 | } | ||
2035 | } | ||
2036 | |||
2037 | /* Parse 'return' statement. */ | ||
2038 | static void parse_return(LexState *ls) | ||
2039 | { | ||
2040 | BCIns ins; | ||
2041 | FuncState *fs = ls->fs; | ||
2042 | lj_lex_next(ls); /* Skip 'return'. */ | ||
2043 | fs->flags |= PROTO_HAS_RETURN; | ||
2044 | if (endofblock(ls->token) || ls->token == ';') { /* Bare return. */ | ||
2045 | ins = BCINS_AD(BC_RET0, 0, 1); | ||
2046 | } else { /* Return with one or more values. */ | ||
2047 | ExpDesc e; /* Receives the _last_ expression in the list. */ | ||
2048 | BCReg nret = expr_list(ls, &e); | ||
2049 | if (nret == 1) { /* Return one result. */ | ||
2050 | if (e.k == VCALL) { /* Check for tail call. */ | ||
2051 | BCIns *ip = bcptr(fs, &e); | ||
2052 | /* It doesn't pay off to add BC_VARGT just for 'return ...'. */ | ||
2053 | if (bc_op(*ip) == BC_VARG) goto notailcall; | ||
2054 | fs->pc--; | ||
2055 | ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT, bc_a(*ip), bc_c(*ip)); | ||
2056 | } else { /* Can return the result from any register. */ | ||
2057 | ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); | ||
2058 | } | ||
2059 | } else { | ||
2060 | if (e.k == VCALL) { /* Append all results from a call. */ | ||
2061 | notailcall: | ||
2062 | setbc_b(bcptr(fs, &e), 0); | ||
2063 | ins = BCINS_AD(BC_RETM, fs->nactvar, e.u.s.aux - fs->nactvar); | ||
2064 | } else { | ||
2065 | expr_tonextreg(fs, &e); /* Force contiguous registers. */ | ||
2066 | ins = BCINS_AD(BC_RET, fs->nactvar, nret+1); | ||
2067 | } | ||
2068 | } | ||
2069 | } | ||
2070 | if (fs->flags & PROTO_CHILD) | ||
2071 | bcemit_AJ(fs, BC_UCLO, 0, 0); /* May need to close upvalues first. */ | ||
2072 | bcemit_INS(fs, ins); | ||
2073 | } | ||
2074 | |||
2075 | /* Parse a block. */ | ||
2076 | static void parse_block(LexState *ls) | ||
2077 | { | ||
2078 | FuncState *fs = ls->fs; | ||
2079 | FuncScope bl; | ||
2080 | scope_begin(fs, &bl, 0); | ||
2081 | parse_chunk(ls); | ||
2082 | lua_assert(bl.breaklist == NO_JMP); | ||
2083 | scope_end(fs); | ||
2084 | } | ||
2085 | |||
2086 | /* -- Assignments --------------------------------------------------------- */ | 2146 | /* -- Assignments --------------------------------------------------------- */ |
2087 | 2147 | ||
2088 | /* List of LHS variables. */ | 2148 | /* List of LHS variables. */ |
@@ -2243,7 +2303,119 @@ static void parse_func(LexState *ls, BCLine line) | |||
2243 | fs->bcbase[fs->pc - 1].line = line; /* Set line for the store. */ | 2303 | fs->bcbase[fs->pc - 1].line = line; /* Set line for the store. */ |
2244 | } | 2304 | } |
2245 | 2305 | ||
2246 | /* -- Loop and conditional statements ------------------------------------- */ | 2306 | /* -- Control transfer statements ----------------------------------------- */ |
2307 | |||
2308 | /* Check for end of block. */ | ||
2309 | static int endofblock(LexToken token) | ||
2310 | { | ||
2311 | switch (token) { | ||
2312 | case TK_else: case TK_elseif: case TK_end: case TK_until: case TK_eof: | ||
2313 | return 1; | ||
2314 | default: | ||
2315 | return 0; | ||
2316 | } | ||
2317 | } | ||
2318 | |||
2319 | /* Parse 'return' statement. */ | ||
2320 | static void parse_return(LexState *ls) | ||
2321 | { | ||
2322 | BCIns ins; | ||
2323 | FuncState *fs = ls->fs; | ||
2324 | lj_lex_next(ls); /* Skip 'return'. */ | ||
2325 | fs->flags |= PROTO_HAS_RETURN; | ||
2326 | if (endofblock(ls->token) || ls->token == ';') { /* Bare return. */ | ||
2327 | ins = BCINS_AD(BC_RET0, 0, 1); | ||
2328 | } else { /* Return with one or more values. */ | ||
2329 | ExpDesc e; /* Receives the _last_ expression in the list. */ | ||
2330 | BCReg nret = expr_list(ls, &e); | ||
2331 | if (nret == 1) { /* Return one result. */ | ||
2332 | if (e.k == VCALL) { /* Check for tail call. */ | ||
2333 | BCIns *ip = bcptr(fs, &e); | ||
2334 | /* It doesn't pay off to add BC_VARGT just for 'return ...'. */ | ||
2335 | if (bc_op(*ip) == BC_VARG) goto notailcall; | ||
2336 | fs->pc--; | ||
2337 | ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT, bc_a(*ip), bc_c(*ip)); | ||
2338 | } else { /* Can return the result from any register. */ | ||
2339 | ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); | ||
2340 | } | ||
2341 | } else { | ||
2342 | if (e.k == VCALL) { /* Append all results from a call. */ | ||
2343 | notailcall: | ||
2344 | setbc_b(bcptr(fs, &e), 0); | ||
2345 | ins = BCINS_AD(BC_RETM, fs->nactvar, e.u.s.aux - fs->nactvar); | ||
2346 | } else { | ||
2347 | expr_tonextreg(fs, &e); /* Force contiguous registers. */ | ||
2348 | ins = BCINS_AD(BC_RET, fs->nactvar, nret+1); | ||
2349 | } | ||
2350 | } | ||
2351 | } | ||
2352 | if (fs->flags & PROTO_CHILD) | ||
2353 | bcemit_AJ(fs, BC_UCLO, 0, 0); /* May need to close upvalues first. */ | ||
2354 | bcemit_INS(fs, ins); | ||
2355 | } | ||
2356 | |||
2357 | /* Parse 'break' statement. */ | ||
2358 | static void parse_break(LexState *ls) | ||
2359 | { | ||
2360 | ls->fs->bl->flags |= FSCOPE_BREAK; | ||
2361 | gola_new(ls, NAME_BREAK, VSTACK_GOTO, bcemit_jmp(ls->fs)); | ||
2362 | } | ||
2363 | |||
2364 | /* Parse 'goto' statement. */ | ||
2365 | static void parse_goto(LexState *ls) | ||
2366 | { | ||
2367 | FuncState *fs = ls->fs; | ||
2368 | GCstr *name = lex_str(ls); | ||
2369 | VarInfo *vl = gola_findlabel(ls, name); | ||
2370 | if (vl) /* Treat backwards goto within same scope like a loop. */ | ||
2371 | bcemit_AJ(fs, BC_LOOP, gola_nactvar(vl), -1); /* No BC range check. */ | ||
2372 | fs->bl->flags |= FSCOPE_GOLA; | ||
2373 | gola_new(ls, name, VSTACK_GOTO, bcemit_jmp(fs)); | ||
2374 | } | ||
2375 | |||
2376 | /* Parse label. */ | ||
2377 | static void parse_label(LexState *ls) | ||
2378 | { | ||
2379 | FuncState *fs = ls->fs; | ||
2380 | GCstr *name; | ||
2381 | MSize idx; | ||
2382 | fs->lasttarget = fs->pc; | ||
2383 | fs->bl->flags |= FSCOPE_GOLA; | ||
2384 | lj_lex_next(ls); /* Skip '::'. */ | ||
2385 | name = lex_str(ls); | ||
2386 | if (gola_findlabel(ls, name)) | ||
2387 | lj_lex_error(ls, 0, LJ_ERR_XLDUP, strdata(name)); | ||
2388 | idx = gola_new(ls, name, VSTACK_LABEL, fs->pc); | ||
2389 | lex_check(ls, TK_label); | ||
2390 | /* Recursively parse trailing statements: labels and ';' (Lua 5.2 only). */ | ||
2391 | for (;;) { | ||
2392 | if (ls->token == TK_label) { | ||
2393 | synlevel_begin(ls); | ||
2394 | parse_label(ls); | ||
2395 | synlevel_end(ls); | ||
2396 | } else if (LJ_52 && ls->token == ';') { | ||
2397 | lj_lex_next(ls); | ||
2398 | } else { | ||
2399 | break; | ||
2400 | } | ||
2401 | } | ||
2402 | /* Trailing label is considered to be outside of scope. */ | ||
2403 | if (endofblock(ls->token) && ls->token != TK_until) | ||
2404 | ls->vstack[idx].endpc = fs->bl->nactvar | VSTACK_LABEL; | ||
2405 | gola_resolve(ls, idx); | ||
2406 | } | ||
2407 | |||
2408 | /* -- Blocks, loops and conditional statements ---------------------------- */ | ||
2409 | |||
2410 | /* Parse a block. */ | ||
2411 | static void parse_block(LexState *ls) | ||
2412 | { | ||
2413 | FuncState *fs = ls->fs; | ||
2414 | FuncScope bl; | ||
2415 | fscope_begin(fs, &bl, 0); | ||
2416 | parse_chunk(ls); | ||
2417 | fscope_end(fs); | ||
2418 | } | ||
2247 | 2419 | ||
2248 | /* Parse 'while' statement. */ | 2420 | /* Parse 'while' statement. */ |
2249 | static void parse_while(LexState *ls, BCLine line) | 2421 | static void parse_while(LexState *ls, BCLine line) |
@@ -2254,13 +2426,13 @@ static void parse_while(LexState *ls, BCLine line) | |||
2254 | lj_lex_next(ls); /* Skip 'while'. */ | 2426 | lj_lex_next(ls); /* Skip 'while'. */ |
2255 | start = fs->lasttarget = fs->pc; | 2427 | start = fs->lasttarget = fs->pc; |
2256 | condexit = expr_cond(ls); | 2428 | condexit = expr_cond(ls); |
2257 | scope_begin(fs, &bl, 1); | 2429 | fscope_begin(fs, &bl, FSCOPE_LOOP); |
2258 | lex_check(ls, TK_do); | 2430 | lex_check(ls, TK_do); |
2259 | loop = bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); | 2431 | loop = bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); |
2260 | parse_block(ls); | 2432 | parse_block(ls); |
2261 | jmp_patch(fs, bcemit_jmp(fs), start); | 2433 | jmp_patch(fs, bcemit_jmp(fs), start); |
2262 | lex_match(ls, TK_end, TK_while, line); | 2434 | lex_match(ls, TK_end, TK_while, line); |
2263 | scope_end(fs); | 2435 | fscope_end(fs); |
2264 | jmp_tohere(fs, condexit); | 2436 | jmp_tohere(fs, condexit); |
2265 | jmp_patchins(fs, loop, fs->pc); | 2437 | jmp_patchins(fs, loop, fs->pc); |
2266 | } | 2438 | } |
@@ -2272,24 +2444,24 @@ static void parse_repeat(LexState *ls, BCLine line) | |||
2272 | BCPos loop = fs->lasttarget = fs->pc; | 2444 | BCPos loop = fs->lasttarget = fs->pc; |
2273 | BCPos condexit; | 2445 | BCPos condexit; |
2274 | FuncScope bl1, bl2; | 2446 | FuncScope bl1, bl2; |
2275 | scope_begin(fs, &bl1, 1); /* Breakable loop scope. */ | 2447 | fscope_begin(fs, &bl1, FSCOPE_LOOP); /* Breakable loop scope. */ |
2276 | scope_begin(fs, &bl2, 0); /* Inner scope. */ | 2448 | fscope_begin(fs, &bl2, 0); /* Inner scope. */ |
2277 | lj_lex_next(ls); /* Skip 'repeat'. */ | 2449 | lj_lex_next(ls); /* Skip 'repeat'. */ |
2278 | bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); | 2450 | bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); |
2279 | parse_chunk(ls); | 2451 | parse_chunk(ls); |
2280 | lex_match(ls, TK_until, TK_repeat, line); | 2452 | lex_match(ls, TK_until, TK_repeat, line); |
2281 | condexit = expr_cond(ls); /* Parse condition (still inside inner scope). */ | 2453 | condexit = expr_cond(ls); /* Parse condition (still inside inner scope). */ |
2282 | if (!bl2.upval) { /* No upvalues? Just end inner scope. */ | 2454 | if (!(bl2.flags & FSCOPE_UPVAL)) { /* No upvalues? Just end inner scope. */ |
2283 | scope_end(fs); | 2455 | fscope_end(fs); |
2284 | } else { /* Otherwise generate: cond: UCLO+JMP out, !cond: UCLO+JMP loop. */ | 2456 | } else { /* Otherwise generate: cond: UCLO+JMP out, !cond: UCLO+JMP loop. */ |
2285 | parse_break(ls); /* Break from loop and close upvalues. */ | 2457 | parse_break(ls); /* Break from loop and close upvalues. */ |
2286 | jmp_tohere(fs, condexit); | 2458 | jmp_tohere(fs, condexit); |
2287 | scope_end(fs); /* End inner scope and close upvalues. */ | 2459 | fscope_end(fs); /* End inner scope and close upvalues. */ |
2288 | condexit = bcemit_jmp(fs); | 2460 | condexit = bcemit_jmp(fs); |
2289 | } | 2461 | } |
2290 | jmp_patch(fs, condexit, loop); /* Jump backwards if !cond. */ | 2462 | jmp_patch(fs, condexit, loop); /* Jump backwards if !cond. */ |
2291 | jmp_patchins(fs, loop, fs->pc); | 2463 | jmp_patchins(fs, loop, fs->pc); |
2292 | scope_end(fs); /* End loop scope. */ | 2464 | fscope_end(fs); /* End loop scope. */ |
2293 | } | 2465 | } |
2294 | 2466 | ||
2295 | /* Parse numeric 'for'. */ | 2467 | /* Parse numeric 'for'. */ |
@@ -2318,11 +2490,11 @@ static void parse_for_num(LexState *ls, GCstr *varname, BCLine line) | |||
2318 | var_add(ls, 3); /* Hidden control variables. */ | 2490 | var_add(ls, 3); /* Hidden control variables. */ |
2319 | lex_check(ls, TK_do); | 2491 | lex_check(ls, TK_do); |
2320 | loop = bcemit_AJ(fs, BC_FORI, base, NO_JMP); | 2492 | loop = bcemit_AJ(fs, BC_FORI, base, NO_JMP); |
2321 | scope_begin(fs, &bl, 0); /* Scope for visible variables. */ | 2493 | fscope_begin(fs, &bl, 0); /* Scope for visible variables. */ |
2322 | var_add(ls, 1); | 2494 | var_add(ls, 1); |
2323 | bcreg_reserve(fs, 1); | 2495 | bcreg_reserve(fs, 1); |
2324 | parse_block(ls); | 2496 | parse_block(ls); |
2325 | scope_end(fs); | 2497 | fscope_end(fs); |
2326 | /* Perform loop inversion. Loop control instructions are at the end. */ | 2498 | /* Perform loop inversion. Loop control instructions are at the end. */ |
2327 | loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP); | 2499 | loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP); |
2328 | fs->bcbase[loopend].line = line; /* Fix line for control ins. */ | 2500 | fs->bcbase[loopend].line = line; /* Fix line for control ins. */ |
@@ -2389,11 +2561,11 @@ static void parse_for_iter(LexState *ls, GCstr *indexname) | |||
2389 | var_add(ls, 3); /* Hidden control variables. */ | 2561 | var_add(ls, 3); /* Hidden control variables. */ |
2390 | lex_check(ls, TK_do); | 2562 | lex_check(ls, TK_do); |
2391 | loop = bcemit_AJ(fs, isnext ? BC_ISNEXT : BC_JMP, base, NO_JMP); | 2563 | loop = bcemit_AJ(fs, isnext ? BC_ISNEXT : BC_JMP, base, NO_JMP); |
2392 | scope_begin(fs, &bl, 0); /* Scope for visible variables. */ | 2564 | fscope_begin(fs, &bl, 0); /* Scope for visible variables. */ |
2393 | var_add(ls, nvars-3); | 2565 | var_add(ls, nvars-3); |
2394 | bcreg_reserve(fs, nvars-3); | 2566 | bcreg_reserve(fs, nvars-3); |
2395 | parse_block(ls); | 2567 | parse_block(ls); |
2396 | scope_end(fs); | 2568 | fscope_end(fs); |
2397 | /* Perform loop inversion. Loop control instructions are at the end. */ | 2569 | /* Perform loop inversion. Loop control instructions are at the end. */ |
2398 | jmp_patchins(fs, loop, fs->pc); | 2570 | jmp_patchins(fs, loop, fs->pc); |
2399 | bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1); | 2571 | bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1); |
@@ -2409,7 +2581,7 @@ static void parse_for(LexState *ls, BCLine line) | |||
2409 | FuncState *fs = ls->fs; | 2581 | FuncState *fs = ls->fs; |
2410 | GCstr *varname; | 2582 | GCstr *varname; |
2411 | FuncScope bl; | 2583 | FuncScope bl; |
2412 | scope_begin(fs, &bl, 1); /* Breakable loop scope. */ | 2584 | fscope_begin(fs, &bl, FSCOPE_LOOP); |
2413 | lj_lex_next(ls); /* Skip 'for'. */ | 2585 | lj_lex_next(ls); /* Skip 'for'. */ |
2414 | varname = lex_str(ls); /* Get first variable name. */ | 2586 | varname = lex_str(ls); /* Get first variable name. */ |
2415 | if (ls->token == '=') | 2587 | if (ls->token == '=') |
@@ -2419,7 +2591,7 @@ static void parse_for(LexState *ls, BCLine line) | |||
2419 | else | 2591 | else |
2420 | err_syntax(ls, LJ_ERR_XFOR); | 2592 | err_syntax(ls, LJ_ERR_XFOR); |
2421 | lex_match(ls, TK_end, TK_for, line); | 2593 | lex_match(ls, TK_end, TK_for, line); |
2422 | scope_end(fs); /* Resolve break list. */ | 2594 | fscope_end(fs); /* Resolve break list. */ |
2423 | } | 2595 | } |
2424 | 2596 | ||
2425 | /* Parse condition and 'then' block. */ | 2597 | /* Parse condition and 'then' block. */ |
@@ -2500,6 +2672,15 @@ static int parse_stmt(LexState *ls) | |||
2500 | lj_lex_next(ls); | 2672 | lj_lex_next(ls); |
2501 | break; | 2673 | break; |
2502 | #endif | 2674 | #endif |
2675 | case TK_label: | ||
2676 | parse_label(ls); | ||
2677 | break; | ||
2678 | case TK_goto: | ||
2679 | if (LJ_52 || lj_lex_lookahead(ls) == TK_name) { | ||
2680 | lj_lex_next(ls); | ||
2681 | parse_goto(ls); | ||
2682 | break; | ||
2683 | } /* else: fallthrough */ | ||
2503 | default: | 2684 | default: |
2504 | parse_call_assign(ls); | 2685 | parse_call_assign(ls); |
2505 | break; | 2686 | break; |
@@ -2526,6 +2707,7 @@ static void parse_chunk(LexState *ls) | |||
2526 | GCproto *lj_parse(LexState *ls) | 2707 | GCproto *lj_parse(LexState *ls) |
2527 | { | 2708 | { |
2528 | FuncState fs; | 2709 | FuncState fs; |
2710 | FuncScope bl; | ||
2529 | GCproto *pt; | 2711 | GCproto *pt; |
2530 | lua_State *L = ls->L; | 2712 | lua_State *L = ls->L; |
2531 | #ifdef LUAJIT_DISABLE_DEBUGINFO | 2713 | #ifdef LUAJIT_DISABLE_DEBUGINFO |
@@ -2542,6 +2724,7 @@ GCproto *lj_parse(LexState *ls) | |||
2542 | fs.bcbase = NULL; | 2724 | fs.bcbase = NULL; |
2543 | fs.bclim = 0; | 2725 | fs.bclim = 0; |
2544 | fs.flags |= PROTO_VARARG; /* Main chunk is always a vararg func. */ | 2726 | fs.flags |= PROTO_VARARG; /* Main chunk is always a vararg func. */ |
2727 | fscope_begin(&fs, &bl, 0); | ||
2545 | bcemit_AD(&fs, BC_FUNCV, 0, 0); /* Placeholder. */ | 2728 | bcemit_AD(&fs, BC_FUNCV, 0, 0); /* Placeholder. */ |
2546 | lj_lex_next(ls); /* Read-ahead first token. */ | 2729 | lj_lex_next(ls); /* Read-ahead first token. */ |
2547 | parse_chunk(ls); | 2730 | parse_chunk(ls); |
diff --git a/src/lj_record.c b/src/lj_record.c index 8718f8bb..7620ae4c 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -550,7 +550,7 @@ static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) | |||
550 | ** an inner loop even in a root trace. But it's better to be a bit | 550 | ** an inner loop even in a root trace. But it's better to be a bit |
551 | ** more conservative here and only do it for very short loops. | 551 | ** more conservative here and only do it for very short loops. |
552 | */ | 552 | */ |
553 | if (!innerloopleft(J, pc)) | 553 | if (bc_j(*pc) != -1 && !innerloopleft(J, pc)) |
554 | lj_trace_err(J, LJ_TRERR_LINNER); /* Root trace hit an inner loop. */ | 554 | lj_trace_err(J, LJ_TRERR_LINNER); /* Root trace hit an inner loop. */ |
555 | if ((ev != LOOPEV_ENTERLO && | 555 | if ((ev != LOOPEV_ENTERLO && |
556 | J->loopref && J->cur.nins - J->loopref > 24) || --J->loopunroll < 0) | 556 | J->loopref && J->cur.nins - J->loopref > 24) || --J->loopunroll < 0) |