diff options
author | Mike Pall <mike> | 2010-11-18 00:23:24 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-11-18 00:23:24 +0100 |
commit | ba602c9578e01b1d692beddf7e974fa70b6eecf2 (patch) | |
tree | 3ec1beecf5205801d9c1048aca92c97b5bafe859 /src/lj_record.c | |
parent | 3754a8fe7a820bcfc5e2633d15c648a194dd4144 (diff) | |
download | luajit-ba602c9578e01b1d692beddf7e974fa70b6eecf2.tar.gz luajit-ba602c9578e01b1d692beddf7e974fa70b6eecf2.tar.bz2 luajit-ba602c9578e01b1d692beddf7e974fa70b6eecf2.zip |
Add support for __pairs and __ipairs metamethods (from Lua 5.2).
Diffstat (limited to 'src/lj_record.c')
-rw-r--r-- | src/lj_record.c | 63 |
1 files changed, 36 insertions, 27 deletions
diff --git a/src/lj_record.c b/src/lj_record.c index 734adcf5..4ff208f8 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -1358,7 +1358,7 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd) | |||
1358 | UNUSED(rd); | 1358 | UNUSED(rd); |
1359 | } | 1359 | } |
1360 | 1360 | ||
1361 | static TValue *recff_tostring_cp(lua_State *L, lua_CFunction dummy, void *ud) | 1361 | static TValue *recff_metacall_cp(lua_State *L, lua_CFunction dummy, void *ud) |
1362 | { | 1362 | { |
1363 | jit_State *J = (jit_State *)ud; | 1363 | jit_State *J = (jit_State *)ud; |
1364 | rec_tailcall(J, 0, 1); | 1364 | rec_tailcall(J, 0, 1); |
@@ -1366,31 +1366,38 @@ static TValue *recff_tostring_cp(lua_State *L, lua_CFunction dummy, void *ud) | |||
1366 | return NULL; | 1366 | return NULL; |
1367 | } | 1367 | } |
1368 | 1368 | ||
1369 | static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm) | ||
1370 | { | ||
1371 | RecordIndex ix; | ||
1372 | ix.tab = J->base[0]; | ||
1373 | copyTV(J->L, &ix.tabv, &rd->argv[0]); | ||
1374 | if (rec_mm_lookup(J, &ix, mm)) { /* Has metamethod? */ | ||
1375 | int errcode; | ||
1376 | /* Temporarily insert metamethod below object. */ | ||
1377 | J->base[1] = J->base[0]; | ||
1378 | J->base[0] = ix.mobj; | ||
1379 | copyTV(J->L, &rd->argv[1], &rd->argv[0]); | ||
1380 | copyTV(J->L, &rd->argv[0], &ix.mobjv); | ||
1381 | /* Need to protect rec_tailcall because it may throw. */ | ||
1382 | errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp); | ||
1383 | /* Always undo Lua stack changes to avoid confusing the interpreter. */ | ||
1384 | copyTV(J->L, &rd->argv[0], &rd->argv[1]); | ||
1385 | if (errcode) | ||
1386 | lj_err_throw(J->L, errcode); /* Propagate errors. */ | ||
1387 | rd->nres = -1; /* Pending call. */ | ||
1388 | return 1; /* Tailcalled to metamethod. */ | ||
1389 | } | ||
1390 | return 0; | ||
1391 | } | ||
1392 | |||
1369 | static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) | 1393 | static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) |
1370 | { | 1394 | { |
1371 | TRef tr = J->base[0]; | 1395 | TRef tr = J->base[0]; |
1372 | if (tref_isstr(tr)) { | 1396 | if (tref_isstr(tr)) { |
1373 | /* Ignore __tostring in the string base metatable. */ | 1397 | /* Ignore __tostring in the string base metatable. */ |
1374 | /* Pass on result in J->base[0]. */ | 1398 | /* Pass on result in J->base[0]. */ |
1375 | } else { | 1399 | } else if (!recff_metacall(J, rd, MM_tostring)) { |
1376 | RecordIndex ix; | 1400 | if (tref_isnumber(tr)) { |
1377 | ix.tab = tr; | ||
1378 | copyTV(J->L, &ix.tabv, &rd->argv[0]); | ||
1379 | if (rec_mm_lookup(J, &ix, MM_tostring)) { /* Has __tostring metamethod? */ | ||
1380 | int errcode; | ||
1381 | /* Temporarily insert metamethod below object. */ | ||
1382 | J->base[1] = tr; | ||
1383 | J->base[0] = ix.mobj; | ||
1384 | copyTV(J->L, &rd->argv[1], &rd->argv[0]); | ||
1385 | copyTV(J->L, &rd->argv[0], &ix.mobjv); | ||
1386 | /* Need to protect rec_tailcall because it may throw. */ | ||
1387 | errcode = lj_vm_cpcall(J->L, NULL, J, recff_tostring_cp); | ||
1388 | /* Always undo Lua stack changes to avoid confusing the interpreter. */ | ||
1389 | copyTV(J->L, &rd->argv[0], &rd->argv[1]); | ||
1390 | if (errcode) | ||
1391 | lj_err_throw(J->L, errcode); /* Propagate errors. */ | ||
1392 | rd->nres = -1; /* Pending call. */ | ||
1393 | } else if (tref_isnumber(tr)) { | ||
1394 | J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); | 1401 | J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); |
1395 | } else if (tref_ispri(tr)) { | 1402 | } else if (tref_ispri(tr)) { |
1396 | J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); | 1403 | 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) | |||
1419 | 1426 | ||
1420 | static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) | 1427 | static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) |
1421 | { | 1428 | { |
1422 | TRef tab = J->base[0]; | 1429 | if (!recff_metacall(J, rd, MM_ipairs)) { |
1423 | if (tref_istab(tab)) { | 1430 | TRef tab = J->base[0]; |
1424 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); | 1431 | if (tref_istab(tab)) { |
1425 | J->base[1] = tab; | 1432 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); |
1426 | J->base[2] = lj_ir_kint(J, 0); | 1433 | J->base[1] = tab; |
1427 | rd->nres = 3; | 1434 | J->base[2] = lj_ir_kint(J, 0); |
1428 | } /* else: Interpreter will throw. */ | 1435 | rd->nres = 3; |
1436 | } /* else: Interpreter will throw. */ | ||
1437 | } | ||
1429 | } | 1438 | } |
1430 | 1439 | ||
1431 | static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd) | 1440 | static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd) |