aboutsummaryrefslogtreecommitdiff
path: root/src/lj_parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_parse.c')
-rw-r--r--src/lj_parse.c100
1 files changed, 67 insertions, 33 deletions
diff --git a/src/lj_parse.c b/src/lj_parse.c
index 1570f833..b063da25 100644
--- a/src/lj_parse.c
+++ b/src/lj_parse.c
@@ -2030,41 +2030,13 @@ static void parse_repeat(LexState *ls, BCLine line)
2030 scope_end(fs); /* End loop scope. */ 2030 scope_end(fs); /* End loop scope. */
2031} 2031}
2032 2032
2033/* Parse body of a 'for' statement. */
2034static void parse_for_body(LexState *ls, BCReg base, BCLine line,
2035 BCReg nvars, int isnum)
2036{
2037 FuncScope bl;
2038 FuncState *fs = ls->fs;
2039 BCPos loop, loopend;
2040 var_add(ls, 3); /* Hidden control variables. */
2041 lex_check(ls, TK_do);
2042 loop = isnum ? bcemit_AJ(fs, BC_FORI, base, NO_JMP) :
2043 bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP);
2044 scope_begin(fs, &bl, 0); /* Scope for visible variables. */
2045 var_add(ls, nvars);
2046 bcreg_reserve(fs, nvars);
2047 parse_block(ls);
2048 scope_end(fs);
2049 /* Perform loop inversion. Loop control instructions are at the end. */
2050 if (isnum) {
2051 loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP);
2052 jmp_patchins(fs, loop, fs->pc);
2053 } else {
2054 jmp_patchins(fs, loop, fs->pc);
2055 bcemit_ABC(fs, BC_ITERC, base+3, nvars+1, 2+1);
2056 loopend = bcemit_AJ(fs, BC_ITERL, base+3, NO_JMP);
2057 fs->bcbase[loopend-1].line = line;
2058 }
2059 fs->bcbase[loopend].line = line; /* Fix line for control ins. */
2060 jmp_patchins(fs, loopend, loop+1);
2061}
2062
2063/* Parse numeric 'for'. */ 2033/* Parse numeric 'for'. */
2064static void parse_for_num(LexState *ls, GCstr *varname, BCLine line) 2034static void parse_for_num(LexState *ls, GCstr *varname, BCLine line)
2065{ 2035{
2066 FuncState *fs = ls->fs; 2036 FuncState *fs = ls->fs;
2067 BCReg base = fs->freereg; 2037 BCReg base = fs->freereg;
2038 FuncScope bl;
2039 BCPos loop, loopend;
2068 /* Hidden control variables. */ 2040 /* Hidden control variables. */
2069 var_new_lit(ls, FORL_IDX, "(for index)"); 2041 var_new_lit(ls, FORL_IDX, "(for index)");
2070 var_new_lit(ls, FORL_STOP, "(for limit)"); 2042 var_new_lit(ls, FORL_STOP, "(for limit)");
@@ -2081,7 +2053,51 @@ static void parse_for_num(LexState *ls, GCstr *varname, BCLine line)
2081 bcemit_AD(fs, BC_KSHORT, fs->freereg, 1); /* Default step is 1. */ 2053 bcemit_AD(fs, BC_KSHORT, fs->freereg, 1); /* Default step is 1. */
2082 bcreg_reserve(fs, 1); 2054 bcreg_reserve(fs, 1);
2083 } 2055 }
2084 parse_for_body(ls, base, line, 1, 1); 2056 var_add(ls, 3); /* Hidden control variables. */
2057 lex_check(ls, TK_do);
2058 loop = bcemit_AJ(fs, BC_FORI, base, NO_JMP);
2059 scope_begin(fs, &bl, 0); /* Scope for visible variables. */
2060 var_add(ls, 1);
2061 bcreg_reserve(fs, 1);
2062 parse_block(ls);
2063 scope_end(fs);
2064 /* Perform loop inversion. Loop control instructions are at the end. */
2065 loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP);
2066 fs->bcbase[loopend].line = line; /* Fix line for control ins. */
2067 jmp_patchins(fs, loopend, loop+1);
2068 jmp_patchins(fs, loop, fs->pc);
2069}
2070
2071/* Try to predict whether the iterator is next() and specialize the bytecode.
2072** Detecting next() and pairs() by name is simplistic, but quite effective.
2073** The interpreter backs off if the check for the closure fails at runtime.
2074*/
2075static int predict_next(LexState *ls, FuncState *fs, BCPos pc)
2076{
2077 BCIns ins = fs->bcbase[pc].ins;
2078 GCstr *name;
2079 cTValue *o;
2080 switch (bc_op(ins)) {
2081 case BC_MOV:
2082 name = gco2str(gcref(var_get(ls, fs, bc_d(ins)).name));
2083 break;
2084 case BC_UGET:
2085 name = gco2str(gcref(ls->vstack[fs->uvloc[bc_d(ins)].vidx].name));
2086 break;
2087 case BC_GGET:
2088 /* There's no inverse index (yet), so lookup the strings. */
2089 o = lj_tab_getstr(fs->kt, lj_str_newlit(ls->L, "pairs"));
2090 if (o && tvisnum(o) && o->u32.lo == bc_d(ins))
2091 return 1;
2092 o = lj_tab_getstr(fs->kt, lj_str_newlit(ls->L, "next"));
2093 if (o && tvisnum(o) && o->u32.lo == bc_d(ins))
2094 return 1;
2095 return 0;
2096 default:
2097 return 0;
2098 }
2099 return (name->len == 5 && !strcmp(strdata(name), "pairs")) ||
2100 (name->len == 4 && !strcmp(strdata(name), "next"));
2085} 2101}
2086 2102
2087/* Parse 'for' iterator. */ 2103/* Parse 'for' iterator. */
@@ -2091,7 +2107,10 @@ static void parse_for_iter(LexState *ls, GCstr *indexname)
2091 ExpDesc e; 2107 ExpDesc e;
2092 BCReg nvars = 0; 2108 BCReg nvars = 0;
2093 BCLine line; 2109 BCLine line;
2094 BCReg base = fs->freereg; 2110 BCReg base = fs->freereg + 3;
2111 BCPos loop, loopend, exprpc = fs->pc;
2112 FuncScope bl;
2113 int isnext;
2095 /* Hidden control variables. */ 2114 /* Hidden control variables. */
2096 var_new_lit(ls, nvars++, "(for generator)"); 2115 var_new_lit(ls, nvars++, "(for generator)");
2097 var_new_lit(ls, nvars++, "(for state)"); 2116 var_new_lit(ls, nvars++, "(for state)");
@@ -2104,7 +2123,22 @@ static void parse_for_iter(LexState *ls, GCstr *indexname)
2104 line = ls->linenumber; 2123 line = ls->linenumber;
2105 assign_adjust(ls, 3, expr_list(ls, &e), &e); 2124 assign_adjust(ls, 3, expr_list(ls, &e), &e);
2106 bcreg_bump(fs, 3); /* The iterator needs another 3 slots (func + 2 args). */ 2125 bcreg_bump(fs, 3); /* The iterator needs another 3 slots (func + 2 args). */
2107 parse_for_body(ls, base, line, nvars - 3, 0); 2126 isnext = (nvars <= 5 && predict_next(ls, fs, exprpc));
2127 var_add(ls, 3); /* Hidden control variables. */
2128 lex_check(ls, TK_do);
2129 loop = bcemit_AJ(fs, isnext ? BC_ISNEXT : BC_JMP, base, NO_JMP);
2130 scope_begin(fs, &bl, 0); /* Scope for visible variables. */
2131 var_add(ls, nvars-3);
2132 bcreg_reserve(fs, nvars-3);
2133 parse_block(ls);
2134 scope_end(fs);
2135 /* Perform loop inversion. Loop control instructions are at the end. */
2136 jmp_patchins(fs, loop, fs->pc);
2137 bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1);
2138 loopend = bcemit_AJ(fs, BC_ITERL, base, NO_JMP);
2139 fs->bcbase[loopend-1].line = line; /* Fix line for control ins. */
2140 fs->bcbase[loopend].line = line;
2141 jmp_patchins(fs, loopend, loop+1);
2108} 2142}
2109 2143
2110/* Parse 'for' statement. */ 2144/* Parse 'for' statement. */