diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_parse.c | 100 |
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. */ | ||
2034 | static 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'. */ |
2064 | static void parse_for_num(LexState *ls, GCstr *varname, BCLine line) | 2034 | static 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 | */ | ||
2075 | static 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. */ |