diff options
author | Mike Pall <mike> | 2024-04-19 01:33:19 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2024-04-19 01:33:19 +0200 |
commit | f5affaa6c4e7524e661484f22f24255f9a83eb47 (patch) | |
tree | f31ad8fb54b3cf6e592b0ea099cb0532b3044edc | |
parent | 7110b935672489afd6ba3eef3e5139d2f3bd05b6 (diff) | |
download | luajit-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.c | 20 | ||||
-rw-r--r-- | src/lj_cdata.c | 2 | ||||
-rw-r--r-- | src/lj_ctype.c | 12 | ||||
-rw-r--r-- | src/lj_ctype.h | 2 | ||||
-rw-r--r-- | src/lj_gc.c | 41 | ||||
-rw-r--r-- | src/lj_obj.h | 3 | ||||
-rw-r--r-- | src/lj_state.c | 3 |
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 | ||
768 | LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to miscmap table. */ | 768 | LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to miscmap table. */ |
769 | 769 | ||
770 | LJLIB_CF(ffi_metatype) | 770 | LJLIB_CF(ffi_metatype) |
771 | { | 771 | { |
@@ -791,8 +791,6 @@ LJLIB_CF(ffi_metatype) | |||
791 | return 1; | 791 | return 1; |
792 | } | 792 | } |
793 | 793 | ||
794 | LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */ | ||
795 | |||
796 | LJLIB_CF(ffi_gc) LJLIB_REC(.) | 794 | LJLIB_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. */ | ||
829 | static 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. */ |
842 | static void ffi_register_module(lua_State *L) | 827 | static 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 | ||
87 | void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it) | 87 | void 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. */ | ||
647 | void 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. */ |
647 | void lj_ctype_freestate(global_State *g) | 659 | void 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); | |||
476 | LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); | 475 | LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); |
477 | LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); | 476 | LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); |
478 | LJ_FUNC CTState *lj_ctype_init(lua_State *L); | 477 | LJ_FUNC CTState *lj_ctype_init(lua_State *L); |
478 | LJ_FUNC void lj_ctype_initfin(lua_State *L); | ||
479 | LJ_FUNC void lj_ctype_freestate(global_State *g); | 479 | LJ_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) | |||
588 | void lj_gc_finalize_cdata(lua_State *L) | 584 | void 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; |