mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
FFI: Add ffi.gc() function for finalization of cdata objects.
This commit is contained in:
parent
cead25f928
commit
83a37aeca7
@ -238,6 +238,34 @@ This functions is mainly useful to override the pointer compatibility
|
|||||||
checks or to convert pointers to addresses or vice versa.
|
checks or to convert pointers to addresses or vice versa.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3 id="ffi_gc"><tt>cdata = ffi.gc(cdata, finalizer)</tt></h3>
|
||||||
|
<p>
|
||||||
|
Associates a finalizer with a pointer or aggregate cdata object. The
|
||||||
|
cdata object is returned unchanged.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This function allows safe integration of unmanaged resources into the
|
||||||
|
automatic memory management of the LuaJIT garbage collector. Typical
|
||||||
|
usage:
|
||||||
|
</p>
|
||||||
|
<pre class="code">
|
||||||
|
local p = ffi.gc(ffi.C.malloc(n), ffi.C.free)
|
||||||
|
...
|
||||||
|
p = nil -- Last reference to p is gone.
|
||||||
|
-- GC will eventually run finalizer: ffi.C.free(p)
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
A cdata finalizer works like the <tt>__gc</tt> metamethod for userdata
|
||||||
|
objects: when the last reference to a cdata object is gone, the
|
||||||
|
associated finalizer is called with the cdata object as an argument. The
|
||||||
|
finalizer can be a Lua function or a cdata function or cdata function
|
||||||
|
pointer. An existing finalizer can be removed by setting a <tt>nil</tt>
|
||||||
|
finalizer, e.g. right before explicitly deleting a resource:
|
||||||
|
</p>
|
||||||
|
<pre class="code">
|
||||||
|
ffi.C.free(ffi.gc(p, nil)) -- Manually free the memory.
|
||||||
|
</pre>
|
||||||
|
|
||||||
<h2 id="info">C Type Information</h2>
|
<h2 id="info">C Type Information</h2>
|
||||||
<p>
|
<p>
|
||||||
The following API functions return information about C types.
|
The following API functions return information about C types.
|
||||||
|
@ -21,9 +21,9 @@ lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
|||||||
lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
|
lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
|
||||||
lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
|
lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
|
||||||
lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
||||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h \
|
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h \
|
||||||
lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h lj_clib.h lj_ff.h \
|
lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h lj_clib.h \
|
||||||
lj_ffdef.h lj_lib.h lj_libdef.h
|
lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
|
||||||
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
|
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
|
||||||
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
||||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
|
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
|
||||||
@ -96,7 +96,7 @@ lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
|||||||
lj_traceerr.h lj_vm.h
|
lj_traceerr.h lj_vm.h
|
||||||
lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||||
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_udata.h lj_meta.h \
|
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_udata.h lj_meta.h \
|
||||||
lj_state.h lj_frame.h lj_bc.h lj_cdata.h lj_ctype.h lj_trace.h lj_jit.h \
|
lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h lj_jit.h \
|
||||||
lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h
|
lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h
|
||||||
lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
lj_gc.h lj_err.h lj_errmsg.h lj_frame.h lj_bc.h lj_jit.h lj_ir.h \
|
lj_gc.h lj_err.h lj_errmsg.h lj_frame.h lj_bc.h lj_jit.h lj_ir.h \
|
||||||
@ -161,7 +161,7 @@ lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
|||||||
lj_vm.h lj_vmevent.h
|
lj_vm.h lj_vmevent.h
|
||||||
ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
|
ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
|
||||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h \
|
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h \
|
||||||
lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_cdata.h lj_ctype.h \
|
lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h \
|
||||||
lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_err.c \
|
lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_err.c \
|
||||||
lj_ff.h lj_ffdef.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c \
|
lj_ff.h lj_ffdef.h lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c \
|
||||||
lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_state.c lj_lex.h \
|
lj_str.c lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_state.c lj_lex.h \
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "lj_gc.h"
|
#include "lj_gc.h"
|
||||||
#include "lj_err.h"
|
#include "lj_err.h"
|
||||||
#include "lj_str.h"
|
#include "lj_str.h"
|
||||||
|
#include "lj_tab.h"
|
||||||
#include "lj_ctype.h"
|
#include "lj_ctype.h"
|
||||||
#include "lj_cparse.h"
|
#include "lj_cparse.h"
|
||||||
#include "lj_cdata.h"
|
#include "lj_cdata.h"
|
||||||
@ -353,6 +354,24 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LJLIB_CF(ffi_cast) LJLIB_REC(ffi_new)
|
||||||
|
{
|
||||||
|
CTState *cts = ctype_cts(L);
|
||||||
|
CTypeID id = ffi_checkctype(L, cts);
|
||||||
|
CType *d = ctype_raw(cts, id);
|
||||||
|
TValue *o = lj_lib_checkany(L, 2);
|
||||||
|
L->top = o+1; /* Make sure this is the last item on the stack. */
|
||||||
|
if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
|
||||||
|
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
||||||
|
if (!(tviscdata(o) && cdataV(o)->typeid == id)) {
|
||||||
|
GCcdata *cd = lj_cdata_new(cts, id, d->size);
|
||||||
|
lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
|
||||||
|
setcdataV(L, o, cd);
|
||||||
|
lj_gc_check(L);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
LJLIB_CF(ffi_typeof)
|
LJLIB_CF(ffi_typeof)
|
||||||
{
|
{
|
||||||
CTState *cts = ctype_cts(L);
|
CTState *cts = ctype_cts(L);
|
||||||
@ -419,24 +438,6 @@ LJLIB_CF(ffi_offsetof)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LJLIB_CF(ffi_cast) LJLIB_REC(ffi_new)
|
|
||||||
{
|
|
||||||
CTState *cts = ctype_cts(L);
|
|
||||||
CTypeID id = ffi_checkctype(L, cts);
|
|
||||||
CType *d = ctype_raw(cts, id);
|
|
||||||
TValue *o = lj_lib_checkany(L, 2);
|
|
||||||
L->top = o+1; /* Make sure this is the last item on the stack. */
|
|
||||||
if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
|
|
||||||
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
|
||||||
if (!(tviscdata(o) && cdataV(o)->typeid == id)) {
|
|
||||||
GCcdata *cd = lj_cdata_new(cts, id, d->size);
|
|
||||||
lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
|
|
||||||
setcdataV(L, o, cd);
|
|
||||||
lj_gc_check(L);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LJLIB_CF(ffi_string) LJLIB_REC(.)
|
LJLIB_CF(ffi_string) LJLIB_REC(.)
|
||||||
{
|
{
|
||||||
CTState *cts = ctype_cts(L);
|
CTState *cts = ctype_cts(L);
|
||||||
@ -520,6 +521,30 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.)
|
|||||||
|
|
||||||
#undef H_
|
#undef H_
|
||||||
|
|
||||||
|
LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to weak table. */
|
||||||
|
|
||||||
|
LJLIB_CF(ffi_gc)
|
||||||
|
{
|
||||||
|
GCcdata *cd = ffi_checkcdata(L, 1);
|
||||||
|
TValue *fin = lj_lib_checkany(L, 2);
|
||||||
|
CTState *cts = ctype_cts(L);
|
||||||
|
GCtab *t = cts->finalizer;
|
||||||
|
CType *ct = ctype_raw(cts, cd->typeid);
|
||||||
|
if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
|
||||||
|
ctype_isrefarray(ct->info)))
|
||||||
|
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
||||||
|
if (gcref(t->metatable)) { /* Update finalizer table, if still enabled. */
|
||||||
|
copyTV(L, lj_tab_set(L, t, L->base), fin);
|
||||||
|
lj_gc_anybarriert(L, t);
|
||||||
|
if (!tvisnil(fin))
|
||||||
|
cd->marked |= LJ_GC_CDATA_FIN;
|
||||||
|
else
|
||||||
|
cd->marked &= ~LJ_GC_CDATA_FIN;
|
||||||
|
}
|
||||||
|
L->top = L->base+1; /* Pass through the cdata object. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */
|
LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */
|
||||||
|
|
||||||
LJLIB_CF(ffi_load)
|
LJLIB_CF(ffi_load)
|
||||||
@ -538,9 +563,23 @@ LJLIB_PUSH(top-2) LJLIB_SET(arch)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* Create special weak-keyed finalizer table. */
|
||||||
|
static GCtab *ffi_finalizer(lua_State *L)
|
||||||
|
{
|
||||||
|
/* NOBARRIER: The table is new (marked white). */
|
||||||
|
GCtab *t = lj_tab_new(L, 0, 1);
|
||||||
|
settabV(L, L->top++, t);
|
||||||
|
setgcref(t->metatable, obj2gco(t));
|
||||||
|
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
|
||||||
|
lj_str_newlit(L, "K"));
|
||||||
|
t->nomm = (uint8_t)(~(1u<<MM_mode));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
LUALIB_API int luaopen_ffi(lua_State *L)
|
LUALIB_API int luaopen_ffi(lua_State *L)
|
||||||
{
|
{
|
||||||
lj_ctype_init(L);
|
CTState *cts = lj_ctype_init(L);
|
||||||
|
cts->finalizer = ffi_finalizer(L);
|
||||||
LJ_LIB_REG(L, NULL, ffi_meta);
|
LJ_LIB_REG(L, NULL, ffi_meta);
|
||||||
/* NOBARRIER: basemt is a GC root. */
|
/* NOBARRIER: basemt is a GC root. */
|
||||||
setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
|
setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
|
||||||
|
@ -52,7 +52,18 @@ GCcdata *lj_cdata_newv(CTState *cts, CTypeID id, CTSize sz, CTSize align)
|
|||||||
/* Free a C data object. */
|
/* Free a C data object. */
|
||||||
void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
|
void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
|
||||||
{
|
{
|
||||||
if (LJ_LIKELY(!cdataisv(cd))) {
|
if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) {
|
||||||
|
GCobj *root;
|
||||||
|
cd->marked = curwhite(g) | LJ_GC_FINALIZED;
|
||||||
|
if ((root = gcref(g->gc.mmudata)) != NULL) {
|
||||||
|
setgcrefr(cd->nextgc, root->gch.nextgc);
|
||||||
|
setgcref(root->gch.nextgc, obj2gco(cd));
|
||||||
|
setgcref(g->gc.mmudata, obj2gco(cd));
|
||||||
|
} else {
|
||||||
|
setgcref(cd->nextgc, obj2gco(cd));
|
||||||
|
setgcref(g->gc.mmudata, obj2gco(cd));
|
||||||
|
}
|
||||||
|
} else if (LJ_LIKELY(!cdataisv(cd))) {
|
||||||
CType *ct = ctype_raw(ctype_ctsG(g), cd->typeid);
|
CType *ct = ctype_raw(ctype_ctsG(g), cd->typeid);
|
||||||
CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
|
CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
|
||||||
lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
|
lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
|
||||||
|
@ -540,7 +540,7 @@ GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size)
|
|||||||
/* -- C type state -------------------------------------------------------- */
|
/* -- C type state -------------------------------------------------------- */
|
||||||
|
|
||||||
/* Initialize C type table and state. */
|
/* Initialize C type table and state. */
|
||||||
void lj_ctype_init(lua_State *L)
|
CTState *lj_ctype_init(lua_State *L)
|
||||||
{
|
{
|
||||||
CTState *cts = lj_mem_newt(L, sizeof(CTState), CTState);
|
CTState *cts = lj_mem_newt(L, sizeof(CTState), CTState);
|
||||||
CType *ct = lj_mem_newvec(L, CTTYPETAB_MIN, CType);
|
CType *ct = lj_mem_newvec(L, CTTYPETAB_MIN, CType);
|
||||||
@ -568,6 +568,7 @@ void lj_ctype_init(lua_State *L)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setmref(G(L)->ctype_state, cts);
|
setmref(G(L)->ctype_state, cts);
|
||||||
|
return cts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free C type table and state. */
|
/* Free C type table and state. */
|
||||||
|
@ -158,6 +158,7 @@ typedef struct CTState {
|
|||||||
MSize sizetab; /* Size of C type table. */
|
MSize sizetab; /* Size of C type table. */
|
||||||
lua_State *L; /* Lua state (needed for errors and allocations). */
|
lua_State *L; /* Lua state (needed for errors and allocations). */
|
||||||
global_State *g; /* Global state. */
|
global_State *g; /* Global state. */
|
||||||
|
GCtab *finalizer; /* Map of cdata to finalizer. */
|
||||||
CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
|
CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
|
||||||
} CTState;
|
} CTState;
|
||||||
|
|
||||||
@ -428,7 +429,7 @@ LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp);
|
|||||||
LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
|
LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
|
||||||
LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
|
LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
|
||||||
LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);
|
LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);
|
||||||
LJ_FUNC void lj_ctype_init(lua_State *L);
|
LJ_FUNC CTState *lj_ctype_init(lua_State *L);
|
||||||
LJ_FUNC void lj_ctype_freestate(global_State *g);
|
LJ_FUNC void lj_ctype_freestate(global_State *g);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
103
src/lj_gc.c
103
src/lj_gc.c
@ -20,6 +20,7 @@
|
|||||||
#include "lj_state.h"
|
#include "lj_state.h"
|
||||||
#include "lj_frame.h"
|
#include "lj_frame.h"
|
||||||
#if LJ_HASFFI
|
#if LJ_HASFFI
|
||||||
|
#include "lj_ctype.h"
|
||||||
#include "lj_cdata.h"
|
#include "lj_cdata.h"
|
||||||
#endif
|
#endif
|
||||||
#include "lj_trace.h"
|
#include "lj_trace.h"
|
||||||
@ -170,8 +171,9 @@ static int gc_traverse_tab(global_State *g, GCtab *t)
|
|||||||
while ((c = *modestr++)) {
|
while ((c = *modestr++)) {
|
||||||
if (c == 'k') weak |= LJ_GC_WEAKKEY;
|
if (c == 'k') weak |= LJ_GC_WEAKKEY;
|
||||||
else if (c == 'v') weak |= LJ_GC_WEAKVAL;
|
else if (c == 'v') weak |= LJ_GC_WEAKVAL;
|
||||||
|
else if (c == 'K') weak = (int)(~0u & ~LJ_GC_WEAKVAL);
|
||||||
}
|
}
|
||||||
if (weak) { /* Weak tables are cleared in the atomic phase. */
|
if (weak > 0) { /* Weak tables are cleared in the atomic phase. */
|
||||||
t->marked = cast_byte((t->marked & ~LJ_GC_WEAK) | weak);
|
t->marked = cast_byte((t->marked & ~LJ_GC_WEAK) | weak);
|
||||||
setgcrefr(t->gclist, g->gc.weak);
|
setgcrefr(t->gclist, g->gc.weak);
|
||||||
setgcref(g->gc.weak, obj2gco(t));
|
setgcref(g->gc.weak, obj2gco(t));
|
||||||
@ -458,53 +460,98 @@ static void gc_clearweak(GCobj *o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finalize one userdata object from mmudata list. */
|
/* Call a userdata or cdata finalizer. */
|
||||||
|
static void gc_call_finalizer(global_State *g, lua_State *L,
|
||||||
|
cTValue *mo, GCobj *o)
|
||||||
|
{
|
||||||
|
/* Save and restore lots of state around the __gc callback. */
|
||||||
|
uint8_t oldh = hook_save(g);
|
||||||
|
MSize oldt = g->gc.threshold;
|
||||||
|
int errcode;
|
||||||
|
TValue *top;
|
||||||
|
lj_trace_abort(g);
|
||||||
|
top = L->top;
|
||||||
|
L->top = top+2;
|
||||||
|
hook_entergc(g); /* Disable hooks and new traces during __gc. */
|
||||||
|
g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */
|
||||||
|
copyTV(L, top, mo);
|
||||||
|
setgcV(L, top+1, o, ~o->gch.gct);
|
||||||
|
errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|o| -> | */
|
||||||
|
hook_restore(g, oldh);
|
||||||
|
g->gc.threshold = oldt; /* Restore GC threshold. */
|
||||||
|
if (errcode)
|
||||||
|
lj_err_throw(L, errcode); /* Propagate errors. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize one userdata or cdata object from the mmudata list. */
|
||||||
static void gc_finalize(lua_State *L)
|
static void gc_finalize(lua_State *L)
|
||||||
{
|
{
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
GCobj *o = gcnext(gcref(g->gc.mmudata));
|
GCobj *o = gcnext(gcref(g->gc.mmudata));
|
||||||
GCudata *ud = gco2ud(o);
|
|
||||||
cTValue *mo;
|
cTValue *mo;
|
||||||
lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */
|
lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */
|
||||||
/* Unchain from list of userdata to be finalized. */
|
/* Unchain from list of userdata to be finalized. */
|
||||||
if (o == gcref(g->gc.mmudata))
|
if (o == gcref(g->gc.mmudata))
|
||||||
setgcrefnull(g->gc.mmudata);
|
setgcrefnull(g->gc.mmudata);
|
||||||
else
|
else
|
||||||
setgcrefr(gcref(g->gc.mmudata)->gch.nextgc, ud->nextgc);
|
setgcrefr(gcref(g->gc.mmudata)->gch.nextgc, o->gch.nextgc);
|
||||||
/* Add it back to the main userdata list and make it white. */
|
|
||||||
setgcrefr(ud->nextgc, mainthread(g)->nextgc);
|
|
||||||
setgcref(mainthread(g)->nextgc, o);
|
|
||||||
makewhite(g, o);
|
makewhite(g, o);
|
||||||
/* Resolve the __gc metamethod. */
|
#if LJ_HASFFI
|
||||||
mo = lj_meta_fastg(g, tabref(ud->metatable), MM_gc);
|
if (o->gch.gct == ~LJ_TCDATA) {
|
||||||
if (mo) {
|
TValue tmp, *tv;
|
||||||
/* Save and restore lots of state around the __gc callback. */
|
setgcrefr(o->gch.nextgc, g->gc.root); /* Add cdata back to the gc list. */
|
||||||
uint8_t oldh = hook_save(g);
|
setgcref(g->gc.root, o);
|
||||||
MSize oldt = g->gc.threshold;
|
/* Resolve finalizer. */
|
||||||
int errcode;
|
setcdataV(L, &tmp, gco2cd(o));
|
||||||
TValue *top;
|
tv = lj_tab_set(L, ctype_ctsG(g)->finalizer, &tmp);
|
||||||
lj_trace_abort(g);
|
if (!tvisnil(tv)) {
|
||||||
top = L->top;
|
copyTV(L, &tmp, tv);
|
||||||
L->top = top+2;
|
setnilV(tv); /* Clear entry in finalizer table. */
|
||||||
hook_entergc(g); /* Disable hooks and new traces during __gc. */
|
gc_call_finalizer(g, L, &tmp, o);
|
||||||
g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */
|
}
|
||||||
copyTV(L, top, mo);
|
return;
|
||||||
setudataV(L, top+1, ud);
|
|
||||||
errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|ud| -> | */
|
|
||||||
hook_restore(g, oldh);
|
|
||||||
g->gc.threshold = oldt; /* Restore GC threshold. */
|
|
||||||
if (errcode)
|
|
||||||
lj_err_throw(L, errcode); /* Propagate errors. */
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
/* Add userdata back to the main userdata list. */
|
||||||
|
setgcrefr(o->gch.nextgc, mainthread(g)->nextgc);
|
||||||
|
setgcref(mainthread(g)->nextgc, o);
|
||||||
|
/* Resolve the __gc metamethod. */
|
||||||
|
mo = lj_meta_fastg(g, tabref(gco2ud(o)->metatable), MM_gc);
|
||||||
|
if (mo)
|
||||||
|
gc_call_finalizer(g, L, mo, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finalize all userdata objects from mmudata list. */
|
/* Finalize all userdata objects from mmudata list. */
|
||||||
void lj_gc_finalizeudata(lua_State *L)
|
void lj_gc_finalize_udata(lua_State *L)
|
||||||
{
|
{
|
||||||
while (gcref(G(L)->gc.mmudata) != NULL)
|
while (gcref(G(L)->gc.mmudata) != NULL)
|
||||||
gc_finalize(L);
|
gc_finalize(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LJ_HASFFI
|
||||||
|
/* Finalize all cdata objects from finalizer table. */
|
||||||
|
void lj_gc_finalize_cdata(lua_State *L)
|
||||||
|
{
|
||||||
|
global_State *g = G(L);
|
||||||
|
CTState *cts = ctype_ctsG(g);
|
||||||
|
if (cts) {
|
||||||
|
GCtab *t = cts->finalizer;
|
||||||
|
Node *node = noderef(t->node);
|
||||||
|
ptrdiff_t i;
|
||||||
|
setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */
|
||||||
|
for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
|
||||||
|
if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) {
|
||||||
|
GCobj *o = gcV(&node[i].key);
|
||||||
|
TValue tmp;
|
||||||
|
o->gch.marked &= ~LJ_GC_CDATA_FIN;
|
||||||
|
copyTV(L, &tmp, &node[i].val);
|
||||||
|
setnilV(&node[i].val);
|
||||||
|
gc_call_finalizer(g, L, &tmp, o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Free all remaining GC objects. */
|
/* Free all remaining GC objects. */
|
||||||
void lj_gc_freeall(global_State *g)
|
void lj_gc_freeall(global_State *g)
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,7 @@ enum {
|
|||||||
#define LJ_GC_FINALIZED 0x08
|
#define LJ_GC_FINALIZED 0x08
|
||||||
#define LJ_GC_WEAKKEY 0x08
|
#define LJ_GC_WEAKKEY 0x08
|
||||||
#define LJ_GC_WEAKVAL 0x10
|
#define LJ_GC_WEAKVAL 0x10
|
||||||
|
#define LJ_GC_CDATA_FIN 0x10
|
||||||
#define LJ_GC_FIXED 0x20
|
#define LJ_GC_FIXED 0x20
|
||||||
#define LJ_GC_SFIXED 0x40
|
#define LJ_GC_SFIXED 0x40
|
||||||
|
|
||||||
@ -42,7 +43,12 @@ enum {
|
|||||||
|
|
||||||
/* Collector. */
|
/* Collector. */
|
||||||
LJ_FUNC size_t lj_gc_separateudata(global_State *g, int all);
|
LJ_FUNC size_t lj_gc_separateudata(global_State *g, int all);
|
||||||
LJ_FUNC void lj_gc_finalizeudata(lua_State *L);
|
LJ_FUNC void lj_gc_finalize_udata(lua_State *L);
|
||||||
|
#if LJ_HASFFI
|
||||||
|
LJ_FUNC void lj_gc_finalize_cdata(lua_State *L);
|
||||||
|
#else
|
||||||
|
#define lj_gc_finalize_cdata(L) UNUSED(L)
|
||||||
|
#endif
|
||||||
LJ_FUNC void lj_gc_freeall(global_State *g);
|
LJ_FUNC void lj_gc_freeall(global_State *g);
|
||||||
LJ_FUNCA int LJ_FASTCALL lj_gc_step(lua_State *L);
|
LJ_FUNCA int LJ_FASTCALL lj_gc_step(lua_State *L);
|
||||||
LJ_FUNCA void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L);
|
LJ_FUNCA void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L);
|
||||||
|
@ -225,7 +225,8 @@ static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud)
|
|||||||
{
|
{
|
||||||
UNUSED(dummy);
|
UNUSED(dummy);
|
||||||
UNUSED(ud);
|
UNUSED(ud);
|
||||||
lj_gc_finalizeudata(L);
|
lj_gc_finalize_udata(L);
|
||||||
|
lj_gc_finalize_cdata(L);
|
||||||
/* Frame pop omitted. */
|
/* Frame pop omitted. */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user