mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-04-19 13:33:26 +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. */
|
||||
setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid));
|
||||
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 {
|
||||
GCcdata *cd;
|
||||
CTSize sz;
|
||||
@ -607,6 +614,9 @@ void lj_cconv_ct_tv(CTState *cts, CType *d,
|
||||
} else if (ctype_isstruct(d->info)) {
|
||||
cconv_struct_tab(cts, d, dp, tabV(o), flags);
|
||||
return;
|
||||
} else if (ctype_isptr(d->info) && ctype_cid(d->info) == CTID_GCTAB) {
|
||||
*(GCtab **)dp = tabV(o);
|
||||
return;
|
||||
} else {
|
||||
goto err_conv;
|
||||
}
|
||||
|
@ -923,8 +923,9 @@ static CTypeID cp_decl_intern(CPState *cp, CPDecl *decl)
|
||||
}
|
||||
}
|
||||
} else if (ctype_isptr(info)) {
|
||||
/* Reject pointer/ref to ref. */
|
||||
if (id && ctype_isref(ctype_raw(cp->cts, id)->info))
|
||||
/* Reject pointer/ref to ref/gctab_t. */
|
||||
if (id && (ctype_isref(ctype_raw(cp->cts, id)->info) ||
|
||||
id == CTID_GCTAB))
|
||||
cp_err(cp, LJ_ERR_FFI_INVTYPE);
|
||||
if (ctype_isref(info)) {
|
||||
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)) {
|
||||
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)) {
|
||||
cts->L = J->L;
|
||||
sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */
|
||||
|
@ -41,6 +41,8 @@
|
||||
_("uintptr_t", UINT_PSZ) \
|
||||
/* From POSIX. */ \
|
||||
_("ssize_t", INT_PSZ) \
|
||||
/* For anchoring Lua tables to C structs */ \
|
||||
_("gctab_t", GCTAB) \
|
||||
/* End of typedef list. */
|
||||
|
||||
/* 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;
|
||||
break;
|
||||
case CT_PTR:
|
||||
if (LJ_UNLIKELY(ctype_cid(info) == CTID_GCTAB)) {
|
||||
ctype_preplit(ctr, "gctab_t");
|
||||
return;
|
||||
}
|
||||
if ((info & CTF_REF)) {
|
||||
ctype_prepc(ctr, '&');
|
||||
} else {
|
||||
|
@ -296,6 +296,7 @@ typedef struct CTState {
|
||||
_(DOUBLE, 8, CT_NUM, CTF_FP|CTALIGN(3)) \
|
||||
_(COMPLEX_FLOAT, 8, CT_ARRAY, CTF_COMPLEX|CTALIGN(2)|CTID_FLOAT) \
|
||||
_(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_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \
|
||||
_(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))
|
||||
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)) {
|
||||
GCupval *uv = gco2uv(o);
|
||||
gc_marktv(g, uvval(uv));
|
||||
if (uv->closed)
|
||||
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 ||
|
||||
gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE,
|
||||
"bad GC type %d", gct);
|
||||
|
Loading…
Reference in New Issue
Block a user