mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-04-19 21:43:27 +00:00
FFI: Allow references of Lua tables in struct
New builtin CType `gctab_t` is introduced to allow references of Lua tables within struct cdata. Pointer to GCtab is stored and transparent conversion is performed between table TValue and gctab_t. Lua tables anchored to FFI structs are visited by GC so they are valid as long as its owner struct cdata is alive. gctab_t CType serves as a handy way to regain access to the owner Lua object from the opaque userdata received in FFI callbacks. Signed-off-by: zyxwvu Shi <i@shiyc.cn>
This commit is contained in:
parent
97813fb924
commit
6788383349
@ -408,6 +408,13 @@ int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
|
|||||||
/* Create reference. */
|
/* Create reference. */
|
||||||
setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid));
|
setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid));
|
||||||
return 1; /* Need GC step. */
|
return 1; /* Need GC step. */
|
||||||
|
} else if (ctype_isptr(sinfo) && ctype_cid(sinfo) == CTID_GCTAB) {
|
||||||
|
GCtab *tab = *(GCtab **)sp;
|
||||||
|
if (tab && tab->gct == ~LJ_TTAB)
|
||||||
|
settabV(cts->L, o, tab);
|
||||||
|
else
|
||||||
|
setnilV(o);
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
GCcdata *cd;
|
GCcdata *cd;
|
||||||
CTSize sz;
|
CTSize sz;
|
||||||
@ -607,6 +614,9 @@ void lj_cconv_ct_tv(CTState *cts, CType *d,
|
|||||||
} else if (ctype_isstruct(d->info)) {
|
} else if (ctype_isstruct(d->info)) {
|
||||||
cconv_struct_tab(cts, d, dp, tabV(o), flags);
|
cconv_struct_tab(cts, d, dp, tabV(o), flags);
|
||||||
return;
|
return;
|
||||||
|
} else if (ctype_isptr(d->info) && ctype_cid(d->info) == CTID_GCTAB) {
|
||||||
|
*(GCtab **)dp = tabV(o);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
goto err_conv;
|
goto err_conv;
|
||||||
}
|
}
|
||||||
|
@ -923,8 +923,9 @@ static CTypeID cp_decl_intern(CPState *cp, CPDecl *decl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ctype_isptr(info)) {
|
} else if (ctype_isptr(info)) {
|
||||||
/* Reject pointer/ref to ref. */
|
/* Reject pointer/ref to ref/gctab_t. */
|
||||||
if (id && ctype_isref(ctype_raw(cp->cts, id)->info))
|
if (id && (ctype_isref(ctype_raw(cp->cts, id)->info) ||
|
||||||
|
id == CTID_GCTAB))
|
||||||
cp_err(cp, LJ_ERR_FFI_INVTYPE);
|
cp_err(cp, LJ_ERR_FFI_INVTYPE);
|
||||||
if (ctype_isref(info)) {
|
if (ctype_isref(info)) {
|
||||||
info &= ~CTF_VOLATILE; /* Refs are always const, never volatile. */
|
info &= ~CTF_VOLATILE; /* Refs are always const, never volatile. */
|
||||||
|
@ -572,6 +572,10 @@ static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp)
|
|||||||
}
|
}
|
||||||
} else if (ctype_isptr(sinfo) || ctype_isenum(sinfo)) {
|
} else if (ctype_isptr(sinfo) || ctype_isenum(sinfo)) {
|
||||||
sp = emitir(IRT(IR_XLOAD, t), sp, 0); /* Box pointers and enums. */
|
sp = emitir(IRT(IR_XLOAD, t), sp, 0); /* Box pointers and enums. */
|
||||||
|
if (LJ_UNLIKELY(ctype_cid(sinfo) == CTID_GCTAB)) {
|
||||||
|
emitir(IRTG(IR_NE, t), sp, lj_ir_kptr(J, NULL));
|
||||||
|
return emitconv(sp, IRT_TAB, t, 0);
|
||||||
|
}
|
||||||
} else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) {
|
} else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) {
|
||||||
cts->L = J->L;
|
cts->L = J->L;
|
||||||
sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */
|
sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
_("uintptr_t", UINT_PSZ) \
|
_("uintptr_t", UINT_PSZ) \
|
||||||
/* From POSIX. */ \
|
/* From POSIX. */ \
|
||||||
_("ssize_t", INT_PSZ) \
|
_("ssize_t", INT_PSZ) \
|
||||||
|
/* For anchoring Lua tables to C structs */ \
|
||||||
|
_("gctab_t", GCTAB) \
|
||||||
/* End of typedef list. */
|
/* End of typedef list. */
|
||||||
|
|
||||||
/* Keywords (only the ones we actually care for). */
|
/* Keywords (only the ones we actually care for). */
|
||||||
@ -509,6 +511,10 @@ static void ctype_repr(CTRepr *ctr, CTypeID id)
|
|||||||
if (ctype_attrib(info) == CTA_QUAL) qual |= size;
|
if (ctype_attrib(info) == CTA_QUAL) qual |= size;
|
||||||
break;
|
break;
|
||||||
case CT_PTR:
|
case CT_PTR:
|
||||||
|
if (LJ_UNLIKELY(ctype_cid(info) == CTID_GCTAB)) {
|
||||||
|
ctype_preplit(ctr, "gctab_t");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ((info & CTF_REF)) {
|
if ((info & CTF_REF)) {
|
||||||
ctype_prepc(ctr, '&');
|
ctype_prepc(ctr, '&');
|
||||||
} else {
|
} else {
|
||||||
|
@ -296,6 +296,7 @@ typedef struct CTState {
|
|||||||
_(DOUBLE, 8, CT_NUM, CTF_FP|CTALIGN(3)) \
|
_(DOUBLE, 8, CT_NUM, CTF_FP|CTALIGN(3)) \
|
||||||
_(COMPLEX_FLOAT, 8, CT_ARRAY, CTF_COMPLEX|CTALIGN(2)|CTID_FLOAT) \
|
_(COMPLEX_FLOAT, 8, CT_ARRAY, CTF_COMPLEX|CTALIGN(2)|CTID_FLOAT) \
|
||||||
_(COMPLEX_DOUBLE, 16, CT_ARRAY, CTF_COMPLEX|CTALIGN(3)|CTID_DOUBLE) \
|
_(COMPLEX_DOUBLE, 16, CT_ARRAY, CTF_COMPLEX|CTALIGN(3)|CTID_DOUBLE) \
|
||||||
|
_(GCTAB, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_GCTAB) \
|
||||||
_(P_VOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_VOID) \
|
_(P_VOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_VOID) \
|
||||||
_(P_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \
|
_(P_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \
|
||||||
_(P_CCHAR, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CCHAR) \
|
_(P_CCHAR, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CCHAR) \
|
||||||
|
15
src/lj_gc.c
15
src/lj_gc.c
@ -75,12 +75,25 @@ static void gc_mark(global_State *g, GCobj *o)
|
|||||||
if (gcref(sbx->dict_mt))
|
if (gcref(sbx->dict_mt))
|
||||||
gc_markobj(g, gcref(sbx->dict_mt));
|
gc_markobj(g, gcref(sbx->dict_mt));
|
||||||
}
|
}
|
||||||
|
} else if (gct == ~LJ_TCDATA) {
|
||||||
|
GCcdata *cd = gco2cd(o);
|
||||||
|
CType *ct = ctype_get(ctype_ctsG(g), cd->ctypeid);
|
||||||
|
if (LJ_UNLIKELY(ctype_isstruct(ct->info))) {
|
||||||
|
while (ct->sib) {
|
||||||
|
ct = ctype_get(ctype_ctsG(g), ct->sib);
|
||||||
|
if (ctype_cid(ct->info) == CTID_GCTAB) {
|
||||||
|
GCobj *t = *(GCobj **)((uintptr_t)cdataptr(cd) + ct->size);
|
||||||
|
if (t && t->gch.gct == ~LJ_TTAB && iswhite(t))
|
||||||
|
gc_mark(g, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) {
|
} else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) {
|
||||||
GCupval *uv = gco2uv(o);
|
GCupval *uv = gco2uv(o);
|
||||||
gc_marktv(g, uvval(uv));
|
gc_marktv(g, uvval(uv));
|
||||||
if (uv->closed)
|
if (uv->closed)
|
||||||
gray2black(o); /* Closed upvalues are never gray. */
|
gray2black(o); /* Closed upvalues are never gray. */
|
||||||
} else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) {
|
} else if (gct != ~LJ_TSTR) {
|
||||||
lj_assertG(gct == ~LJ_TFUNC || gct == ~LJ_TTAB ||
|
lj_assertG(gct == ~LJ_TFUNC || gct == ~LJ_TTAB ||
|
||||||
gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE,
|
gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE,
|
||||||
"bad GC type %d", gct);
|
"bad GC type %d", gct);
|
||||||
|
Loading…
Reference in New Issue
Block a user