From efbb767ddd15349896957c785b99d964bd5b5e77 Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Tue, 23 Apr 2019 10:33:36 +0200 Subject: [PATCH] Restructure mark functionality for the Julia GC. --- src/julia_gc.c | 37 ++++++++++++++++++++++++------------- src/julia_gc.h | 14 +++++++++++++- src/weakptr.c | 19 ++++++++++++++++++- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/julia_gc.c b/src/julia_gc.c index 26947a8689b..0686b747e4c 100644 --- a/src/julia_gc.c +++ b/src/julia_gc.c @@ -459,12 +459,10 @@ void InitMarkFuncBags(UInt type, TNumMarkFuncBags mark_func) TabMarkFuncBags[type] = mark_func; } -static inline int JMarkGapObjSafe(void * obj) +static inline int JMarkTyped(void * obj, jl_datatype_t * ty) { // only traverse objects internally used by GAP - void *ty = jl_typeof(obj); - if (ty != datatype_mptr && ty != datatype_bag - && ty != datatype_largebag && ty != jl_weakref_type) + if (!jl_typeis(obj, ty)) return 0; return jl_gc_mark_queue_obj(JuliaTLS, (jl_value_t *)obj); } @@ -581,7 +579,11 @@ static void TryMark(void * p) if (jl_typeis(p2, datatype_mptr)) JMark(p2); #else - JMarkGapObjSafe(p2); + void *ty = jl_typeof(p2); + if (ty != datatype_mptr && ty != datatype_bag + && ty != datatype_largebag && ty != jl_weakref_type) + return; + JMark(p2); #endif } } @@ -755,7 +757,7 @@ static void PostGCHook(int full) // the Julia marking function for master pointer objects (i.e., this function // is called by the Julia GC whenever it marks a GAP master pointer object) -static uintptr_t JMarkMPtr(jl_ptls_t ptls, jl_value_t * obj) +static uintptr_t MPtrMarkFunc(jl_ptls_t ptls, jl_value_t * obj) { if (!*(void **)obj) return 0; @@ -772,7 +774,7 @@ static uintptr_t JMarkMPtr(jl_ptls_t ptls, jl_value_t * obj) // the Julia marking function for bags (i.e., this function is called by the // Julia GC whenever it marks a GAP bag object) -static uintptr_t JMarkBag(jl_ptls_t ptls, jl_value_t * obj) +static uintptr_t BagMarkFunc(jl_ptls_t ptls, jl_value_t * obj) { BagHeader * hdr = (BagHeader *)obj; Bag contents = (Bag)(hdr + 1); @@ -812,12 +814,12 @@ void InitBags(UInt initial_size, Bag * stack_bottom, UInt stack_align) jl_set_const(jl_main_module, jl_symbol("ForeignGAP"), (jl_value_t *)Module); datatype_mptr = jl_new_foreign_type(jl_symbol("MPtr"), Module, - jl_any_type, JMarkMPtr, NULL, 1, 0); + jl_any_type, MPtrMarkFunc, NULL, 1, 0); datatype_bag = jl_new_foreign_type(jl_symbol("Bag"), Module, jl_any_type, - JMarkBag, JFinalizer, 1, 0); + BagMarkFunc, JFinalizer, 1, 0); datatype_largebag = jl_new_foreign_type(jl_symbol("LargeBag"), Module, jl_any_type, - JMarkBag, JFinalizer, 1, 1); + BagMarkFunc, JFinalizer, 1, 1); // export datatypes to Julia level jl_set_const(Module, jl_symbol("MPtr"), (jl_value_t *)datatype_mptr); @@ -1021,20 +1023,29 @@ inline void MarkBag(Bag bag) // relies on Julia internals. It is functionally equivalent // to: // - // if (JMarkGapObjSafe(p)) YoungRef++; + // if (JMarkTyped(p, datatype_mptr)) YoungRef++; // switch (jl_astaggedvalue(p)->bits.gc) { case 0: - if (JMarkGapObjSafe(p)) + if (JMarkTyped(p, datatype_mptr)) YoungRef++; break; case 1: YoungRef++; break; case 2: - JMarkGapObjSafe(p); + JMarkTyped(p, datatype_mptr); break; case 3: break; } } + +void MarkJuliaWeakRef(void * p) +{ + // If `jl_nothing` gets passed in as an argument, it will not + // be marked. This is harmless, because `jl_nothing` will always + // be live regardless. + if (JMarkTyped(p, jl_weakref_type)) + YoungRef++; +} diff --git a/src/julia_gc.h b/src/julia_gc.h index 18a9a15e6f7..7f16b23b73d 100644 --- a/src/julia_gc.h +++ b/src/julia_gc.h @@ -17,7 +17,9 @@ ** *F MarkJuliaObj() . . . . . . . . . . . . . . . . . . mark Julia object ** -** 'MarkJuliaObjSafe' marks a Julia object; the argument can be NULL. +** 'MarkJuliaObjSafe' marks a Julia object; the argument can be NULL. No +** further checks are performed. If is not a Julia object, a crash +** may result. */ void MarkJuliaObj(void * obj); @@ -33,4 +35,14 @@ void MarkJuliaObj(void * obj); void MarkJuliaObjSafe(void * obj); +/**************************************************************************** +** +*F MarkJuliaWeakRef() . . . . . . . . . . . mark Julia weak reference +** +** 'MarkJuliaWeakRef` marks a Julia weak reference. This must be a valid +** reference and cannot be NULL. +*/ + +void MarkJuliaWeakRef(void * obj); + #endif diff --git a/src/weakptr.c b/src/weakptr.c index fda3962dc33..9d1c1ed9032 100644 --- a/src/weakptr.c +++ b/src/weakptr.c @@ -39,6 +39,7 @@ #ifdef USE_JULIA_GC #include "julia.h" +#include "julia_gc.h" #endif #define RequireWPObj(funcname, op) \ @@ -552,6 +553,22 @@ static void SweepWeakPointerObj( Bag *src, Bag *dst, UInt len) #endif +#ifdef USE_JULIA_GC + +static void MarkWeakPointerObj(Obj wp) +{ + // can't use the stored length here, in case we are in the middle of + // copying + const UInt len = SIZE_BAG(wp) / sizeof(Obj) - 1; + for (UInt i = 1; i <= len; i++) { + Bag elm = CONST_ADDR_OBJ(wp)[i]; + if (IS_BAG_REF(elm)) + MarkJuliaWeakRef(elm); + } +} + +#endif + #ifdef USE_THREADSAFE_COPYING #ifndef WARD_ENABLED @@ -832,7 +849,7 @@ static Int InitKernel ( InitMarkFuncBags ( T_WPOBJ, MarkWeakPointerObj ); InitSweepFuncBags( T_WPOBJ, SweepWeakPointerObj ); #elif defined(USE_JULIA_GC) - InitMarkFuncBags ( T_WPOBJ, MarkAllButFirstSubBags ); + InitMarkFuncBags ( T_WPOBJ, MarkWeakPointerObj ); #else #error Unknown garbage collector implementation, no weak pointer object implemention available #endif