From 8b71ab108053c12bc2de9c1de0f786387a2b75e5 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Wed, 20 Jun 2012 18:24:49 +0200 Subject: FFI: Check for __new metamethod when calling a constructor. --- src/lib_ffi.c | 41 ++++++++++++++++++++++------------------- src/lj_crecord.c | 44 +++++++++++++++++++++++++------------------- src/lj_obj.h | 8 +++++++- 3 files changed, 54 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/lib_ffi.c b/src/lib_ffi.c index f4097041..e7d31fe7 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c @@ -206,31 +206,34 @@ LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat) return ffi_arith(L); } -/* Handle ctype __call metamethod. */ -static int ffi_call_meta(lua_State *L, CTypeID id) -{ - CTState *cts = ctype_cts(L); - CType *ct = ctype_raw(cts, id); - cTValue *tv; - if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, MM_call); - if (!tv) - lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL))); - return lj_meta_tailcall(L, tv); -} - /* Forward declaration. */ static int lj_cf_ffi_new(lua_State *L); LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) { + CTState *cts = ctype_cts(L); GCcdata *cd = ffi_checkcdata(L, 1); - int ret; - if (cd->typeid == CTID_CTYPEID) - return lj_cf_ffi_new(L); - if ((ret = lj_ccall_func(L, cd)) < 0) - return ffi_call_meta(L, cd->typeid); - return ret; + CTypeID id = cd->typeid; + CType *ct; + cTValue *tv; + MMS mm = MM_call; + if (cd->typeid == CTID_CTYPEID) { + id = *(CTypeID *)cdataptr(cd); + mm = MM_new; + } else { + int ret = lj_ccall_func(L, cd); + if (ret >= 0) + return ret; + } + /* Handle ctype __call/__new metamethod. */ + ct = ctype_raw(cts, id); + if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); + tv = lj_ctype_meta(cts, id, mm); + if (tv) + return lj_meta_tailcall(L, tv); + else if (mm == MM_call) + lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL))); + return lj_cf_ffi_new(L); } LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add) diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 3097cbf0..95d09e48 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c @@ -941,30 +941,36 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd) return 0; } -/* Record ctype call metamethod. */ -static void crec_call_meta(jit_State *J, RecordFFData *rd, CTypeID id) +void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) { CTState *cts = ctype_ctsG(J2G(J)); - CType *ct = ctype_raw(cts, id); + GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); + CTypeID id = cd->typeid; + CType *ct; cTValue *tv; + MMS mm = MM_call; + if (id == CTID_CTYPEID) { + id = crec_constructor(J, cd, J->base[0]); + mm = MM_new; + } else if (crec_call(J, rd, cd)) { + return; + } + /* Record ctype __call/__new metamethod. */ + ct = ctype_raw(cts, id); if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); - tv = lj_ctype_meta(cts, id, MM_call); - if (tv && tvisfunc(tv)) { - J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; - rd->nres = -1; /* Pending tailcall. */ - } else { - /* NYI: non-function metamethods. */ - lj_trace_err(J, LJ_TRERR_BADTYPE); + tv = lj_ctype_meta(cts, id, mm); + if (tv) { + if (tvisfunc(tv)) { + J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; + rd->nres = -1; /* Pending tailcall. */ + return; + } + } else if (mm == MM_new) { + crec_alloc(J, rd, id); + return; } -} - -void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) -{ - GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); - if (cd->typeid == CTID_CTYPEID) - crec_alloc(J, rd, crec_constructor(J, cd, J->base[0])); - else if (!crec_call(J, rd, cd)) - crec_call_meta(J, rd, cd->typeid); + /* No metamethod or NYI: non-function metamethods. */ + lj_trace_err(J, LJ_TRERR_BADTYPE); } static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) diff --git a/src/lj_obj.h b/src/lj_obj.h index 43ed9204..d7e8ec09 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -437,6 +437,12 @@ enum { #define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st) /* Metamethods. ORDER MM */ +#ifdef LJ_HASFFI +#define MMDEF_FFI(_) _(new) +#else +#define MMDEF_FFI(_) +#endif + #ifdef LUAJIT_ENABLE_LUA52COMPAT #define MMDEF_52(_) _(pairs) _(ipairs) #else @@ -450,7 +456,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) MMDEF_52(_) + _(metatable) _(tostring) MMDEF_FFI(_) MMDEF_52(_) typedef enum { #define MMENUM(name) MM_##name, -- cgit v1.2.3-55-g6feb