mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 23:24:09 +00:00
Add support for __pairs and __ipairs metamethods (from Lua 5.2).
This commit is contained in:
parent
3754a8fe7a
commit
ba602c9578
@ -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
@ -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
|
||||
|
1040
src/buildvm_x86.h
1040
src/buildvm_x86.h
File diff suppressed because it is too large
Load Diff
@ -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 -------------------------------- */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,13 +1426,15 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
|
||||
|
||||
static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd)
|
||||
{
|
||||
TRef tab = J->base[0];
|
||||
if (tref_istab(tab)) {
|
||||
J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
|
||||
J->base[1] = tab;
|
||||
J->base[2] = lj_ir_kint(J, 0);
|
||||
rd->nres = 3;
|
||||
} /* else: Interpreter will throw. */
|
||||
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]));
|
||||
J->base[1] = tab;
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user