@@ -323,6 +323,24 @@ JL_DLLEXPORT void jl_gc_prepare_to_collect(void)
323323 errno = last_errno ;
324324}
325325
326+ JL_DLLEXPORT unsigned char jl_gc_pin_object (void * obj ) {
327+ return mmtk_pin_object (obj );
328+ }
329+
330+ JL_DLLEXPORT void jl_gc_notify_thread_yield (jl_ptls_t ptls , void * ctx ) {
331+ if (ctx == NULL ) {
332+ // Save the context for the thread as it was running at the time of the call
333+ int r = getcontext (& ptls -> gc_tls .ctx_at_the_time_gc_started );
334+ if (r == -1 ) {
335+ jl_safe_printf ("Failed to save context for conservative scanning\n" );
336+ abort ();
337+ }
338+ return ;
339+ }
340+ memcpy (& ptls -> gc_tls .ctx_at_the_time_gc_started , ctx , sizeof (ucontext_t ));
341+ }
342+
343+
326344// ========================================================================= //
327345// GC Statistics
328346// ========================================================================= //
@@ -807,6 +825,36 @@ JL_DLLEXPORT int* jl_gc_get_have_pending_finalizers(void) {
807825 return (int * )& jl_gc_have_pending_finalizers ;
808826}
809827
828+
829+ // ========================================================================= //
830+ // Write barriers
831+ // ========================================================================= //
832+
833+ // No inline write barrier -- only used for debugging
834+ JL_DLLEXPORT void jl_gc_wb1_noinline (const void * parent ) JL_NOTSAFEPOINT
835+ {
836+ jl_gc_wb_back (parent );
837+ }
838+
839+ JL_DLLEXPORT void jl_gc_wb2_noinline (const void * parent , const void * ptr ) JL_NOTSAFEPOINT
840+ {
841+ jl_gc_wb (parent , ptr );
842+ }
843+
844+ JL_DLLEXPORT void jl_gc_wb1_slow (const void * parent ) JL_NOTSAFEPOINT
845+ {
846+ jl_task_t * ct = jl_current_task ;
847+ jl_ptls_t ptls = ct -> ptls ;
848+ mmtk_object_reference_write_slow (& ptls -> gc_tls .mmtk_mutator , parent , (const void * ) 0 );
849+ }
850+
851+ JL_DLLEXPORT void jl_gc_wb2_slow (const void * parent , const void * ptr ) JL_NOTSAFEPOINT
852+ {
853+ jl_task_t * ct = jl_current_task ;
854+ jl_ptls_t ptls = ct -> ptls ;
855+ mmtk_object_reference_write_slow (& ptls -> gc_tls .mmtk_mutator , parent , ptr );
856+ }
857+
810858// ========================================================================= //
811859// Allocation
812860// ========================================================================= //
@@ -842,29 +890,43 @@ STATIC_INLINE void* bump_alloc_fast(MMTkMutatorContext* mutator, uintptr_t* curs
842890 }
843891}
844892
893+ inline void mmtk_set_side_metadata (const void * side_metadata_base , void * obj ) {
894+ intptr_t addr = (intptr_t ) obj ;
895+ uint8_t * meta_addr = (uint8_t * ) side_metadata_base + (addr >> 6 );
896+ intptr_t shift = (addr >> 3 ) & 0b111 ;
897+ while (1 ) {
898+ uint8_t old_val = * meta_addr ;
899+ uint8_t new_val = old_val | (1 << shift );
900+ if (jl_atomic_cmpswap ((_Atomic (uint8_t )* )meta_addr , & old_val , new_val )) {
901+ break ;
902+ }
903+ }
904+ }
905+
845906STATIC_INLINE void * mmtk_immix_alloc_fast (MMTkMutatorContext * mutator , size_t size , size_t align , size_t offset ) {
846907 ImmixAllocator * allocator = & mutator -> allocators .immix [MMTK_DEFAULT_IMMIX_ALLOCATOR ];
847908 return bump_alloc_fast (mutator , (uintptr_t * )& allocator -> cursor , (intptr_t )allocator -> limit , size , align , offset , 0 );
848909}
849910
850- inline void mmtk_immix_post_alloc_slow (MMTkMutatorContext * mutator , void * obj , size_t size ) {
851- mmtk_post_alloc (mutator , obj , size , 0 );
852- }
853-
854911STATIC_INLINE void mmtk_immix_post_alloc_fast (MMTkMutatorContext * mutator , void * obj , size_t size ) {
855- // FIXME: for now, we do nothing
856- // but when supporting moving, this is where we set the valid object (VO) bit
912+ if (MMTK_NEEDS_VO_BIT ) {
913+ mmtk_set_side_metadata (MMTK_SIDE_VO_BIT_BASE_ADDRESS , obj );
914+ }
857915}
858916
859917STATIC_INLINE void * mmtk_immortal_alloc_fast (MMTkMutatorContext * mutator , size_t size , size_t align , size_t offset ) {
860918 BumpAllocator * allocator = & mutator -> allocators .bump_pointer [MMTK_IMMORTAL_BUMP_ALLOCATOR ];
861919 return bump_alloc_fast (mutator , (uintptr_t * )& allocator -> cursor , (uintptr_t )allocator -> limit , size , align , offset , 1 );
862920}
863921
864- STATIC_INLINE void mmtk_immortal_post_alloc_fast (MMTkMutatorContext * mutator , void * obj , size_t size ) {
865- // FIXME: Similarly, for now, we do nothing
866- // but when supporting moving, this is where we set the valid object (VO) bit
867- // and log (old gen) bit
922+ STATIC_INLINE void mmtk_immortal_post_alloc_fast (MMTkMutatorContext * mutator , void * obj , size_t size ) {
923+ if (MMTK_NEEDS_WRITE_BARRIER == MMTK_OBJECT_BARRIER ) {
924+ mmtk_set_side_metadata (MMTK_SIDE_LOG_BIT_BASE_ADDRESS , obj );
925+ }
926+
927+ if (MMTK_NEEDS_VO_BIT ) {
928+ mmtk_set_side_metadata (MMTK_SIDE_VO_BIT_BASE_ADDRESS , obj );
929+ }
868930}
869931
870932JL_DLLEXPORT jl_value_t * jl_mmtk_gc_alloc_default (jl_ptls_t ptls , int osize , size_t align , void * ty )
@@ -1042,6 +1104,16 @@ jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT
10421104 return jl_valueof (o );
10431105}
10441106
1107+ jl_value_t * jl_gc_permsymbol (size_t sz ) JL_NOTSAFEPOINT
1108+ {
1109+ jl_taggedvalue_t * tag = (jl_taggedvalue_t * )jl_gc_perm_alloc (sz , 0 , sizeof (void * ), 0 );
1110+ jl_value_t * sym = jl_valueof (tag );
1111+ jl_ptls_t ptls = jl_current_task -> ptls ;
1112+ jl_set_typetagof (sym , jl_symbol_tag , 0 ); // We need to set symbol tag. The GC tag doesnt matter.
1113+ mmtk_immortal_post_alloc_fast (& ptls -> gc_tls .mmtk_mutator , sym , sz );
1114+ return sym ;
1115+ }
1116+
10451117JL_DLLEXPORT void * jl_gc_managed_malloc (size_t sz )
10461118{
10471119 jl_ptls_t ptls = jl_current_task -> ptls ;
@@ -1079,6 +1151,11 @@ void jl_gc_notify_image_load(const char* img_data, size_t len)
10791151 mmtk_set_vm_space ((void * )img_data , len );
10801152}
10811153
1154+ void jl_gc_notify_image_alloc (const char * img_data , size_t len )
1155+ {
1156+ mmtk_immortal_region_post_alloc ((void * )img_data , len );
1157+ }
1158+
10821159// ========================================================================= //
10831160// Code specific to stock that is not supported by MMTk
10841161// ========================================================================= //
@@ -1208,6 +1285,53 @@ JL_DLLEXPORT jl_value_t *jl_gc_internal_obj_base_ptr(void *p)
12081285 return NULL ;
12091286}
12101287
1288+ #define jl_p_gcpreserve_stack (jl_current_task->gcpreserve_stack)
1289+
1290+ // This macro currently uses malloc instead of alloca because this function will exit
1291+ // after pushing the roots into the gc_preserve_stack, which means that the preserve_begin function's
1292+ // stack frame will be destroyed (together with its alloca variables). When we support lowering this code
1293+ // inside the same function that is doing the preserve_begin/preserve_end calls we should be able to simple use allocas.
1294+ // Note also that we use a separate stack for gc preserve roots to avoid the possibility of calling free
1295+ // on a stack that has been allocated with alloca instead of malloc, which could happen depending on the order in which
1296+ // JL_GC_POP() and jl_gc_preserve_end_hook() occurs.
1297+
1298+ #define JL_GC_PUSHARGS_PRESERVE_ROOT_OBJS (rts_var ,n ) \
1299+ rts_var = ((jl_value_t**)malloc(((n)+2)*sizeof(jl_value_t*)))+2; \
1300+ ((void**)rts_var)[-2] = (void*)JL_GC_ENCODE_PUSHARGS(n); \
1301+ ((void**)rts_var)[-1] = jl_p_gcpreserve_stack; \
1302+ memset((void*)rts_var, 0, (n)*sizeof(jl_value_t*)); \
1303+ jl_p_gcpreserve_stack = (jl_gcframe_t*)&(((void**)rts_var)[-2]); \
1304+
1305+ #define JL_GC_POP_PRESERVE_ROOT_OBJS () \
1306+ jl_gcframe_t *curr = jl_p_gcpreserve_stack; \
1307+ if(curr) { \
1308+ (jl_p_gcpreserve_stack = jl_p_gcpreserve_stack->prev); \
1309+ free(curr); \
1310+ }
1311+
1312+ // Add each argument as a tpin root object.
1313+ // However, we cannot use JL_GC_PUSH and JL_GC_POP since the slots should live
1314+ // beyond this function. Instead, we maintain a tpin stack by mallocing/freeing
1315+ // the frames for each of the preserve regions we encounter
1316+ JL_DLLEXPORT void jl_gc_preserve_begin_hook (int n , ...) JL_NOTSAFEPOINT
1317+ {
1318+ jl_value_t * * frame ;
1319+ JL_GC_PUSHARGS_PRESERVE_ROOT_OBJS (frame , n );
1320+ if (n == 0 ) return ;
1321+
1322+ va_list args ;
1323+ va_start (args , n );
1324+ for (int i = 0 ; i < n ; i ++ ) {
1325+ frame [i ] = va_arg (args , jl_value_t * );
1326+ }
1327+ va_end (args );
1328+ }
1329+
1330+ JL_DLLEXPORT void jl_gc_preserve_end_hook (void ) JL_NOTSAFEPOINT
1331+ {
1332+ JL_GC_POP_PRESERVE_ROOT_OBJS ();
1333+ }
1334+
12111335#ifdef __cplusplus
12121336}
12131337#endif
0 commit comments