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
| lwz PC, FRAME_PC(BASE)
| checkfail ->fff_fallback
| lwz TAB:TMP2, TAB:CARG1->metatable
| evldd CFUNC:TMP0, CFUNC:RB->upvalue[0]
| cmplwi TAB:TMP2, 0
| la RA, -8(BASE)
| bne ->fff_fallback
| evstdd TAB:CARG1, 0(BASE)
| evstdd TISNIL, 8(BASE)
| li RD, (3+1)*8
@ -1150,8 +1153,11 @@ static void build_subroutines(BuildCtx *ctx)
| checktab TAB:CARG1
| lwz PC, FRAME_PC(BASE)
| checkfail ->fff_fallback
| lwz TAB:TMP2, TAB:CARG1->metatable
| evldd CFUNC:TMP0, CFUNC:RB->upvalue[0]
| cmplwi TAB:TMP2, 0
| la RA, -8(BASE)
| bne ->fff_fallback
| evsplati TMP1, 0
| evstdd TAB:CARG1, 0(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
|
|.ffunc_1 pairs
| mov CFUNC:RB, [BASE-8]
| mov TAB:RB, [BASE]
| 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 PC, [BASE-4]
| mov dword [BASE-4], LJ_TFUNC
@ -1571,8 +1573,10 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse)
| jmp ->fff_res
|
|.ffunc_1 ipairs
| mov CFUNC:RB, [BASE-8]
| mov TAB:RB, [BASE]
| 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 PC, [BASE-4]
| 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)
{
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;
}
LJLIB_PUSH(lastcl)
LJLIB_ASM_(pairs)
LJLIB_NOREGUV LJLIB_ASM_(ipairs_aux) LJLIB_REC(.)
LJLIB_PUSH(lastcl)
LJLIB_ASM_(ipairs) LJLIB_REC(.)
LJLIB_ASM(ipairs) LJLIB_REC(.)
{
return ffh_pairs(L, MM_ipairs);
}
/* -- Base library: throw and catch errors -------------------------------- */

View File

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

View File

@ -1358,7 +1358,7 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *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;
rec_tailcall(J, 0, 1);
@ -1366,31 +1366,38 @@ static TValue *recff_tostring_cp(lua_State *L, lua_CFunction dummy, void *ud)
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)
{
TRef tr = J->base[0];
if (tref_isstr(tr)) {
/* Ignore __tostring in the string base metatable. */
/* Pass on result in J->base[0]. */
} else {
RecordIndex ix;
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)) {
} else if (!recff_metacall(J, rd, MM_tostring)) {
if (tref_isnumber(tr)) {
J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0);
} else if (tref_ispri(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)
{
if (!recff_metacall(J, rd, MM_ipairs)) {
TRef tab = J->base[0];
if (tref_istab(tab)) {
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);
rd->nres = 3;
} /* else: Interpreter will throw. */
}
}
static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd)