Add support for __pairs and __ipairs metamethods (from Lua 5.2).

This commit is contained in:
Mike Pall 2010-11-18 00:23:24 +01:00
parent 3754a8fe7a
commit ba602c9578
9 changed files with 1748 additions and 1685 deletions

View File

@ -1098,8 +1098,11 @@ static void build_subroutines(BuildCtx *ctx)
| checktab TAB:CARG1 | checktab TAB:CARG1
| lwz PC, FRAME_PC(BASE) | lwz PC, FRAME_PC(BASE)
| checkfail ->fff_fallback | checkfail ->fff_fallback
| lwz TAB:TMP2, TAB:CARG1->metatable
| evldd CFUNC:TMP0, CFUNC:RB->upvalue[0] | evldd CFUNC:TMP0, CFUNC:RB->upvalue[0]
| cmplwi TAB:TMP2, 0
| la RA, -8(BASE) | la RA, -8(BASE)
| bne ->fff_fallback
| evstdd TAB:CARG1, 0(BASE) | evstdd TAB:CARG1, 0(BASE)
| evstdd TISNIL, 8(BASE) | evstdd TISNIL, 8(BASE)
| li RD, (3+1)*8 | li RD, (3+1)*8
@ -1150,8 +1153,11 @@ static void build_subroutines(BuildCtx *ctx)
| checktab TAB:CARG1 | checktab TAB:CARG1
| lwz PC, FRAME_PC(BASE) | lwz PC, FRAME_PC(BASE)
| checkfail ->fff_fallback | checkfail ->fff_fallback
| lwz TAB:TMP2, TAB:CARG1->metatable
| evldd CFUNC:TMP0, CFUNC:RB->upvalue[0] | evldd CFUNC:TMP0, CFUNC:RB->upvalue[0]
| cmplwi TAB:TMP2, 0
| la RA, -8(BASE) | la RA, -8(BASE)
| bne ->fff_fallback
| evsplati TMP1, 0 | evsplati TMP1, 0
| evstdd TAB:CARG1, 0(BASE) | evstdd TAB:CARG1, 0(BASE)
| evstdd TMP1, 8(BASE) | evstdd TMP1, 8(BASE)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1509,8 +1509,10 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
| jmp ->fff_res1 | jmp ->fff_res1
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| mov CFUNC:RB, [BASE-8] | mov TAB:RB, [BASE]
| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
| cmp dword TAB:RB->metatable, 0; jne ->fff_fallback
| mov CFUNC:RB, [BASE-8]
| mov CFUNC:RD, CFUNC:RB->upvalue[0] | mov CFUNC:RD, CFUNC:RB->upvalue[0]
| mov PC, [BASE-4] | mov PC, [BASE-4]
| mov dword [BASE-4], LJ_TFUNC | mov dword [BASE-4], LJ_TFUNC
@ -1571,8 +1573,10 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
| jmp ->fff_res | jmp ->fff_res
| |
|.ffunc_1 ipairs |.ffunc_1 ipairs
| mov CFUNC:RB, [BASE-8] | mov TAB:RB, [BASE]
| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
| cmp dword TAB:RB->metatable, 0; jne ->fff_fallback
| mov CFUNC:RB, [BASE-8]
| mov CFUNC:RD, CFUNC:RB->upvalue[0] | mov CFUNC:RD, CFUNC:RB->upvalue[0]
| mov PC, [BASE-4] | mov PC, [BASE-4]
| mov dword [BASE-4], LJ_TFUNC | mov dword [BASE-4], LJ_TFUNC

File diff suppressed because it is too large Load Diff

View File

@ -246,17 +246,43 @@ LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
LJLIB_ASM(next) LJLIB_ASM(next)
{ {
lj_lib_checktab(L, 1); lj_lib_checktab(L, 1);
lj_lib_checknum(L, 2); /* For ipairs_aux. */ return FFH_UNREACHABLE;
}
static int ffh_pairs(lua_State *L, MMS mm)
{
TValue *o = lj_lib_checkany(L, 1);
cTValue *mo = lj_meta_lookup(L, o, mm);
if (!tvisnil(mo)) {
L->top = o+1; /* Only keep one argument. */
copyTV(L, L->base-1, mo); /* Replace callable. */
return FFH_TAILCALL;
} else {
if (!tvistab(o)) lj_err_argt(L, 1, LUA_TTABLE);
setfuncV(L, o-1, funcV(lj_lib_upvalue(L, 1)));
if (mm == MM_pairs) setnilV(o+1); else setintV(o+1, 0);
return FFH_RES(3);
}
}
LJLIB_PUSH(lastcl)
LJLIB_ASM(pairs)
{
return ffh_pairs(L, MM_pairs);
}
LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checknum(L, 2);
return FFH_UNREACHABLE; return FFH_UNREACHABLE;
} }
LJLIB_PUSH(lastcl) LJLIB_PUSH(lastcl)
LJLIB_ASM_(pairs) LJLIB_ASM(ipairs) LJLIB_REC(.)
{
LJLIB_NOREGUV LJLIB_ASM_(ipairs_aux) LJLIB_REC(.) return ffh_pairs(L, MM_ipairs);
}
LJLIB_PUSH(lastcl)
LJLIB_ASM_(ipairs) LJLIB_REC(.)
/* -- Base library: throw and catch errors -------------------------------- */ /* -- Base library: throw and catch errors -------------------------------- */

View File

@ -417,7 +417,7 @@ enum {
/* The following must be in ORDER ARITH. */ \ /* The following must be in ORDER ARITH. */ \
_(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \ _(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \
/* The following are used in the standard libraries. */ \ /* The following are used in the standard libraries. */ \
_(metatable) _(tostring) _(metatable) _(tostring) _(pairs) _(ipairs)
typedef enum { typedef enum {
#define MMENUM(name) MM_##name, #define MMENUM(name) MM_##name,

View File

@ -1358,7 +1358,7 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd)
UNUSED(rd); UNUSED(rd);
} }
static TValue *recff_tostring_cp(lua_State *L, lua_CFunction dummy, void *ud) static TValue *recff_metacall_cp(lua_State *L, lua_CFunction dummy, void *ud)
{ {
jit_State *J = (jit_State *)ud; jit_State *J = (jit_State *)ud;
rec_tailcall(J, 0, 1); rec_tailcall(J, 0, 1);
@ -1366,31 +1366,38 @@ static TValue *recff_tostring_cp(lua_State *L, lua_CFunction dummy, void *ud)
return NULL; return NULL;
} }
static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm)
{
RecordIndex ix;
ix.tab = J->base[0];
copyTV(J->L, &ix.tabv, &rd->argv[0]);
if (rec_mm_lookup(J, &ix, mm)) { /* Has metamethod? */
int errcode;
/* Temporarily insert metamethod below object. */
J->base[1] = J->base[0];
J->base[0] = ix.mobj;
copyTV(J->L, &rd->argv[1], &rd->argv[0]);
copyTV(J->L, &rd->argv[0], &ix.mobjv);
/* Need to protect rec_tailcall because it may throw. */
errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp);
/* Always undo Lua stack changes to avoid confusing the interpreter. */
copyTV(J->L, &rd->argv[0], &rd->argv[1]);
if (errcode)
lj_err_throw(J->L, errcode); /* Propagate errors. */
rd->nres = -1; /* Pending call. */
return 1; /* Tailcalled to metamethod. */
}
return 0;
}
static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
{ {
TRef tr = J->base[0]; TRef tr = J->base[0];
if (tref_isstr(tr)) { if (tref_isstr(tr)) {
/* Ignore __tostring in the string base metatable. */ /* Ignore __tostring in the string base metatable. */
/* Pass on result in J->base[0]. */ /* Pass on result in J->base[0]. */
} else { } else if (!recff_metacall(J, rd, MM_tostring)) {
RecordIndex ix; if (tref_isnumber(tr)) {
ix.tab = tr;
copyTV(J->L, &ix.tabv, &rd->argv[0]);
if (rec_mm_lookup(J, &ix, MM_tostring)) { /* Has __tostring metamethod? */
int errcode;
/* Temporarily insert metamethod below object. */
J->base[1] = tr;
J->base[0] = ix.mobj;
copyTV(J->L, &rd->argv[1], &rd->argv[0]);
copyTV(J->L, &rd->argv[0], &ix.mobjv);
/* Need to protect rec_tailcall because it may throw. */
errcode = lj_vm_cpcall(J->L, NULL, J, recff_tostring_cp);
/* Always undo Lua stack changes to avoid confusing the interpreter. */
copyTV(J->L, &rd->argv[0], &rd->argv[1]);
if (errcode)
lj_err_throw(J->L, errcode); /* Propagate errors. */
rd->nres = -1; /* Pending call. */
} else if (tref_isnumber(tr)) {
J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0);
} else if (tref_ispri(tr)) { } else if (tref_ispri(tr)) {
J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)]));
@ -1419,6 +1426,7 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd)
{ {
if (!recff_metacall(J, rd, MM_ipairs)) {
TRef tab = J->base[0]; TRef tab = J->base[0];
if (tref_istab(tab)) { if (tref_istab(tab)) {
J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
@ -1426,6 +1434,7 @@ static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd)
J->base[2] = lj_ir_kint(J, 0); J->base[2] = lj_ir_kint(J, 0);
rd->nres = 3; rd->nres = 3;
} /* else: Interpreter will throw. */ } /* else: Interpreter will throw. */
}
} }
static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd) static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd)