aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2024-04-19 01:33:19 +0200
committerMike Pall <mike>2024-04-19 01:33:19 +0200
commitf5affaa6c4e7524e661484f22f24255f9a83eb47 (patch)
treef31ad8fb54b3cf6e592b0ea099cb0532b3044edc
parent7110b935672489afd6ba3eef3e5139d2f3bd05b6 (diff)
downloadluajit-f5affaa6c4e7524e661484f22f24255f9a83eb47.tar.gz
luajit-f5affaa6c4e7524e661484f22f24255f9a83eb47.tar.bz2
luajit-f5affaa6c4e7524e661484f22f24255f9a83eb47.zip
FFI: Turn FFI finalizer table into a proper GC root.
Reported by Sergey Bronnikov. #1168
-rw-r--r--src/lib_ffi.c20
-rw-r--r--src/lj_cdata.c2
-rw-r--r--src/lj_ctype.c12
-rw-r--r--src/lj_ctype.h2
-rw-r--r--src/lj_gc.c41
-rw-r--r--src/lj_obj.h3
-rw-r--r--src/lj_state.c3
7 files changed, 39 insertions, 44 deletions
diff --git a/src/lib_ffi.c b/src/lib_ffi.c
index ba783173..fb7f86f3 100644
--- a/src/lib_ffi.c
+++ b/src/lib_ffi.c
@@ -513,7 +513,7 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
513 /* Handle ctype __gc metamethod. Use the fast lookup here. */ 513 /* Handle ctype __gc metamethod. Use the fast lookup here. */
514 cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id); 514 cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
515 if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) { 515 if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
516 GCtab *t = cts->finalizer; 516 GCtab *t = tabref(G(L)->gcroot[GCROOT_FFI_FIN]);
517 if (gcref(t->metatable)) { 517 if (gcref(t->metatable)) {
518 /* Add to finalizer table, if still enabled. */ 518 /* Add to finalizer table, if still enabled. */
519 copyTV(L, lj_tab_set(L, t, o-1), tv); 519 copyTV(L, lj_tab_set(L, t, o-1), tv);
@@ -765,7 +765,7 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.)
765 return 1; 765 return 1;
766} 766}
767 767
768LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to miscmap table. */ 768LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to miscmap table. */
769 769
770LJLIB_CF(ffi_metatype) 770LJLIB_CF(ffi_metatype)
771{ 771{
@@ -791,8 +791,6 @@ LJLIB_CF(ffi_metatype)
791 return 1; 791 return 1;
792} 792}
793 793
794LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */
795
796LJLIB_CF(ffi_gc) LJLIB_REC(.) 794LJLIB_CF(ffi_gc) LJLIB_REC(.)
797{ 795{
798 GCcdata *cd = ffi_checkcdata(L, 1); 796 GCcdata *cd = ffi_checkcdata(L, 1);
@@ -825,19 +823,6 @@ LJLIB_PUSH(top-2) LJLIB_SET(arch)
825 823
826/* ------------------------------------------------------------------------ */ 824/* ------------------------------------------------------------------------ */
827 825
828/* Create special weak-keyed finalizer table. */
829static GCtab *ffi_finalizer(lua_State *L)
830{
831 /* NOBARRIER: The table is new (marked white). */
832 GCtab *t = lj_tab_new(L, 0, 1);
833 settabV(L, L->top++, t);
834 setgcref(t->metatable, obj2gco(t));
835 setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
836 lj_str_newlit(L, "k"));
837 t->nomm = (uint8_t)(~(1u<<MM_mode));
838 return t;
839}
840
841/* Register FFI module as loaded. */ 826/* Register FFI module as loaded. */
842static void ffi_register_module(lua_State *L) 827static void ffi_register_module(lua_State *L)
843{ 828{
@@ -853,7 +838,6 @@ LUALIB_API int luaopen_ffi(lua_State *L)
853{ 838{
854 CTState *cts = lj_ctype_init(L); 839 CTState *cts = lj_ctype_init(L);
855 settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1))); 840 settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
856 cts->finalizer = ffi_finalizer(L);
857 LJ_LIB_REG(L, NULL, ffi_meta); 841 LJ_LIB_REG(L, NULL, ffi_meta);
858 /* NOBARRIER: basemt is a GC root. */ 842 /* NOBARRIER: basemt is a GC root. */
859 setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1))); 843 setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
diff --git a/src/lj_cdata.c b/src/lj_cdata.c
index 77d9730f..2879e2a8 100644
--- a/src/lj_cdata.c
+++ b/src/lj_cdata.c
@@ -86,7 +86,7 @@ void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
86 86
87void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it) 87void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it)
88{ 88{
89 GCtab *t = ctype_ctsG(G(L))->finalizer; 89 GCtab *t = tabref(G(L)->gcroot[GCROOT_FFI_FIN]);
90 if (gcref(t->metatable)) { 90 if (gcref(t->metatable)) {
91 /* Add cdata to finalizer table, if still enabled. */ 91 /* Add cdata to finalizer table, if still enabled. */
92 TValue *tv, tmp; 92 TValue *tv, tmp;
diff --git a/src/lj_ctype.c b/src/lj_ctype.c
index 8a4a55f8..0f6baac9 100644
--- a/src/lj_ctype.c
+++ b/src/lj_ctype.c
@@ -643,6 +643,18 @@ CTState *lj_ctype_init(lua_State *L)
643 return cts; 643 return cts;
644} 644}
645 645
646/* Create special weak-keyed finalizer table. */
647void lj_ctype_initfin(lua_State *L)
648{
649 /* NOBARRIER: The table is new (marked white). */
650 GCtab *t = lj_tab_new(L, 0, 1);
651 setgcref(t->metatable, obj2gco(t));
652 setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
653 lj_str_newlit(L, "k"));
654 t->nomm = (uint8_t)(~(1u<<MM_mode));
655 setgcref(G(L)->gcroot[GCROOT_FFI_FIN], obj2gco(t));
656}
657
646/* Free C type table and state. */ 658/* Free C type table and state. */
647void lj_ctype_freestate(global_State *g) 659void lj_ctype_freestate(global_State *g)
648{ 660{
diff --git a/src/lj_ctype.h b/src/lj_ctype.h
index cde1cf01..d53c4ea4 100644
--- a/src/lj_ctype.h
+++ b/src/lj_ctype.h
@@ -177,7 +177,6 @@ typedef struct CTState {
177 MSize sizetab; /* Size of C type table. */ 177 MSize sizetab; /* Size of C type table. */
178 lua_State *L; /* Lua state (needed for errors and allocations). */ 178 lua_State *L; /* Lua state (needed for errors and allocations). */
179 global_State *g; /* Global state. */ 179 global_State *g; /* Global state. */
180 GCtab *finalizer; /* Map of cdata to finalizer. */
181 GCtab *miscmap; /* Map of -CTypeID to metatable and cb slot to func. */ 180 GCtab *miscmap; /* Map of -CTypeID to metatable and cb slot to func. */
182 CCallback cb; /* Temporary callback state. */ 181 CCallback cb; /* Temporary callback state. */
183 CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */ 182 CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
@@ -476,6 +475,7 @@ LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
476LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); 475LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
477LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); 476LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);
478LJ_FUNC CTState *lj_ctype_init(lua_State *L); 477LJ_FUNC CTState *lj_ctype_init(lua_State *L);
478LJ_FUNC void lj_ctype_initfin(lua_State *L);
479LJ_FUNC void lj_ctype_freestate(global_State *g); 479LJ_FUNC void lj_ctype_freestate(global_State *g);
480 480
481#endif 481#endif
diff --git a/src/lj_gc.c b/src/lj_gc.c
index eebc751b..9cabdef0 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -108,9 +108,6 @@ static void gc_mark_start(global_State *g)
108 gc_markobj(g, tabref(mainthread(g)->env)); 108 gc_markobj(g, tabref(mainthread(g)->env));
109 gc_marktv(g, &g->registrytv); 109 gc_marktv(g, &g->registrytv);
110 gc_mark_gcroot(g); 110 gc_mark_gcroot(g);
111#if LJ_HASFFI
112 if (ctype_ctsG(g)) gc_markobj(g, ctype_ctsG(g)->finalizer);
113#endif
114 g->gc.state = GCSpropagate; 111 g->gc.state = GCSpropagate;
115} 112}
116 113
@@ -190,8 +187,7 @@ static int gc_traverse_tab(global_State *g, GCtab *t)
190 } 187 }
191 if (weak) { /* Weak tables are cleared in the atomic phase. */ 188 if (weak) { /* Weak tables are cleared in the atomic phase. */
192#if LJ_HASFFI 189#if LJ_HASFFI
193 CTState *cts = ctype_ctsG(g); 190 if (gcref(g->gcroot[GCROOT_FFI_FIN]) == obj2gco(t)) {
194 if (cts && cts->finalizer == t) {
195 weak = (int)(~0u & ~LJ_GC_WEAKVAL); 191 weak = (int)(~0u & ~LJ_GC_WEAKVAL);
196 } else 192 } else
197#endif 193#endif
@@ -556,7 +552,7 @@ static void gc_finalize(lua_State *L)
556 o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; 552 o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN;
557 /* Resolve finalizer. */ 553 /* Resolve finalizer. */
558 setcdataV(L, &tmp, gco2cd(o)); 554 setcdataV(L, &tmp, gco2cd(o));
559 tv = lj_tab_set(L, ctype_ctsG(g)->finalizer, &tmp); 555 tv = lj_tab_set(L, tabref(g->gcroot[GCROOT_FFI_FIN]), &tmp);
560 if (!tvisnil(tv)) { 556 if (!tvisnil(tv)) {
561 g->gc.nocdatafin = 0; 557 g->gc.nocdatafin = 0;
562 copyTV(L, &tmp, tv); 558 copyTV(L, &tmp, tv);
@@ -588,23 +584,20 @@ void lj_gc_finalize_udata(lua_State *L)
588void lj_gc_finalize_cdata(lua_State *L) 584void lj_gc_finalize_cdata(lua_State *L)
589{ 585{
590 global_State *g = G(L); 586 global_State *g = G(L);
591 CTState *cts = ctype_ctsG(g); 587 GCtab *t = tabref(g->gcroot[GCROOT_FFI_FIN]);
592 if (cts) { 588 Node *node = noderef(t->node);
593 GCtab *t = cts->finalizer; 589 ptrdiff_t i;
594 Node *node = noderef(t->node); 590 setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */
595 ptrdiff_t i; 591 for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
596 setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */ 592 if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) {
597 for (i = (ptrdiff_t)t->hmask; i >= 0; i--) 593 GCobj *o = gcV(&node[i].key);
598 if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) { 594 TValue tmp;
599 GCobj *o = gcV(&node[i].key); 595 makewhite(g, o);
600 TValue tmp; 596 o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN;
601 makewhite(g, o); 597 copyTV(L, &tmp, &node[i].val);
602 o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; 598 setnilV(&node[i].val);
603 copyTV(L, &tmp, &node[i].val); 599 gc_call_finalizer(g, L, &tmp, o);
604 setnilV(&node[i].val); 600 }
605 gc_call_finalizer(g, L, &tmp, o);
606 }
607 }
608} 601}
609#endif 602#endif
610 603
@@ -720,7 +713,7 @@ static size_t gc_onestep(lua_State *L)
720 return GCFINALIZECOST; 713 return GCFINALIZECOST;
721 } 714 }
722#if LJ_HASFFI 715#if LJ_HASFFI
723 if (!g->gc.nocdatafin) lj_tab_rehash(L, ctype_ctsG(g)->finalizer); 716 if (!g->gc.nocdatafin) lj_tab_rehash(L, tabref(g->gcroot[GCROOT_FFI_FIN]));
724#endif 717#endif
725 g->gc.state = GCSpause; /* End of GC cycle. */ 718 g->gc.state = GCSpause; /* End of GC cycle. */
726 g->gc.debt = 0; 719 g->gc.debt = 0;
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 2d4386e1..c0817663 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -579,6 +579,9 @@ typedef enum {
579 GCROOT_BASEMT_NUM = GCROOT_BASEMT + ~LJ_TNUMX, 579 GCROOT_BASEMT_NUM = GCROOT_BASEMT + ~LJ_TNUMX,
580 GCROOT_IO_INPUT, /* Userdata for default I/O input file. */ 580 GCROOT_IO_INPUT, /* Userdata for default I/O input file. */
581 GCROOT_IO_OUTPUT, /* Userdata for default I/O output file. */ 581 GCROOT_IO_OUTPUT, /* Userdata for default I/O output file. */
582#if LJ_HASFFI
583 GCROOT_FFI_FIN, /* FFI finalizer table. */
584#endif
582 GCROOT_MAX 585 GCROOT_MAX
583} GCRootID; 586} GCRootID;
584 587
diff --git a/src/lj_state.c b/src/lj_state.c
index af17e4b5..6fd7d9ce 100644
--- a/src/lj_state.c
+++ b/src/lj_state.c
@@ -196,6 +196,9 @@ static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud)
196 lj_lex_init(L); 196 lj_lex_init(L);
197 fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */ 197 fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */
198 g->gc.threshold = 4*g->gc.total; 198 g->gc.threshold = 4*g->gc.total;
199#if LJ_HASFFI
200 lj_ctype_initfin(L);
201#endif
199 lj_trace_initstate(g); 202 lj_trace_initstate(g);
200 lj_err_verify(); 203 lj_err_verify();
201 return NULL; 204 return NULL;