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