From 5d096dcfdef5ddb0e6dd67e155adf893df7d7809 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Wed, 20 Apr 2011 01:53:26 +0200 Subject: [PATCH] FFI: Add ffi.istype() function. --- doc/ext_ffi_api.html | 18 ++++++++++++++++++ src/lib_ffi.c | 30 ++++++++++++++++++++++++++++++ src/lj_crecord.c | 39 ++++++++++++++++++++++++++------------- src/lj_crecord.h | 2 ++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html index 2b6d1d86..b1b42878 100644 --- a/doc/ext_ffi_api.html +++ b/doc/ext_ffi_api.html @@ -316,6 +316,24 @@ of ct, which must be a struct. Additionally returns the position and the field size (in bits) for bit fields.

+

status = ffi.istype(ct, obj)

+

+Returns true if obj has the C type given by +ct. Returns false otherwise. +

+

+C type qualifiers (const etc.) are ignored. Pointers are +checked with the standard pointer compatibility rules, but without any +special treatment for void *. If ct specifies a +struct/union, then a pointer to this type is accepted, +too. Otherwise the types must match exactly. +

+

+Note: this function accepts all kinds of Lua objects for the +obj argument, but always returns false for non-cdata +objects. +

+

Utility Functions

str = ffi.string(ptr [,len])

diff --git a/src/lib_ffi.c b/src/lib_ffi.c index fe84ca7d..27996f0e 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c @@ -456,6 +456,36 @@ LJLIB_CF(ffi_typeof) return 1; } +LJLIB_CF(ffi_istype) LJLIB_REC(ffi_istype) +{ + CTState *cts = ctype_cts(L); + CTypeID id1 = ffi_checkctype(L, cts); + TValue *o = lj_lib_checkany(L, 2); + int b = 0; + if (tviscdata(o)) { + GCcdata *cd = cdataV(o); + CTypeID id2 = cd->typeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : + cd->typeid; + CType *ct1 = lj_ctype_rawref(cts, id1); + CType *ct2 = lj_ctype_rawref(cts, id2); + if (ct1 == ct2) { + b = 1; + } else if (ctype_type(ct1->info) == ctype_type(ct2->info) && + ct1->size == ct2->size) { + if (ctype_ispointer(ct1->info)) + b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL); + else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info)) + b = (((ct1->info ^ ct2->info) & ~CTF_QUAL) == 0); + } else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) && + ct1 == ctype_rawchild(cts, ct2)) { + b = 1; + } + } + setboolV(L->top-1, b); + setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */ + return 1; +} + LJLIB_CF(ffi_sizeof) { CTState *cts = ctype_cts(L); diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 83c57063..8330faaf 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c @@ -51,6 +51,18 @@ static GCcdata *argv2cdata(jit_State *J, TRef tr, cTValue *o) return cd; } +/* Specialize to the CTypeID held by a cdata constructor. */ +static CTypeID crec_constructor(jit_State *J, GCcdata *cd, TRef tr) +{ + CTypeID id; + lua_assert(tref_iscdata(tr) && cd->typeid == CTID_CTYPEID); + id = *(CTypeID *)cdataptr(cd); + tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); + tr = emitir(IRT(IR_XLOAD, IRT_INT), tr, 0); + emitir(IRTG(IR_EQ, IRT_INT), tr, lj_ir_kint(J, (int32_t)id)); + return id; +} + static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o) { if (tref_isstr(tr)) { @@ -70,7 +82,8 @@ static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o) return cp.val.id; } else { GCcdata *cd = argv2cdata(J, tr, o); - return cd->typeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->typeid; + return cd->typeid == CTID_CTYPEID ? crec_constructor(J, cd, tr) : + cd->typeid; } } @@ -427,18 +440,6 @@ doconv: /* -- C data metamethods -------------------------------------------------- */ -/* Specialize to the CTypeID held by a cdata constructor. */ -static CTypeID crec_constructor(jit_State *J, GCcdata *cd, TRef tr) -{ - CTypeID id; - lua_assert(tref_iscdata(tr) && cd->typeid == CTID_CTYPEID); - id = *(CTypeID *)cdataptr(cd); - tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); - tr = emitir(IRT(IR_XLOAD, IRT_INT), tr, 0); - emitir(IRTG(IR_EQ, IRT_INT), tr, lj_ir_kint(J, (int32_t)id)); - return id; -} - /* This would be rather difficult in FOLD, so do it here: ** (base+k)+(idx*sz)+ofs ==> (base+idx*sz)+(ofs+k) ** (base+(idx+k)*sz)+ofs ==> (base+idx*sz)+(ofs+k*sz) @@ -1100,6 +1101,18 @@ void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd) } /* else: interpreter will throw. */ } +void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd) +{ + argv2ctype(J, J->base[0], &rd->argv[0]); + if (tref_iscdata(J->base[1])) { + argv2ctype(J, J->base[1], &rd->argv[1]); + J->postproc = LJ_POST_FIXBOOL; + J->base[0] = TREF_TRUE; + } else { + J->base[0] = TREF_FALSE; + } +} + void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd) { if (tref_isstr(J->base[0])) { diff --git a/src/lj_crecord.h b/src/lj_crecord.h index 0199e0eb..fce45afe 100644 --- a/src/lj_crecord.h +++ b/src/lj_crecord.h @@ -19,6 +19,7 @@ LJ_FUNC void LJ_FASTCALL recff_ffi_new(jit_State *J, RecordFFData *rd); LJ_FUNC void LJ_FASTCALL recff_ffi_string(jit_State *J, RecordFFData *rd); LJ_FUNC void LJ_FASTCALL recff_ffi_copy(jit_State *J, RecordFFData *rd); LJ_FUNC void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd); +LJ_FUNC void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd); LJ_FUNC void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd); LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); #else @@ -30,6 +31,7 @@ LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); #define recff_ffi_string recff_nyi #define recff_ffi_copy recff_nyi #define recff_ffi_fill recff_nyi +#define recff_ffi_istype recff_nyi #define recff_ffi_abi recff_nyi #endif