@@ -323,6 +323,24 @@ JL_DLLEXPORT void jl_gc_prepare_to_collect(void)
323
323
errno = last_errno ;
324
324
}
325
325
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
+
326
344
// ========================================================================= //
327
345
// GC Statistics
328
346
// ========================================================================= //
@@ -807,6 +825,36 @@ JL_DLLEXPORT int* jl_gc_get_have_pending_finalizers(void) {
807
825
return (int * )& jl_gc_have_pending_finalizers ;
808
826
}
809
827
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
+
810
858
// ========================================================================= //
811
859
// Allocation
812
860
// ========================================================================= //
@@ -842,29 +890,43 @@ STATIC_INLINE void* bump_alloc_fast(MMTkMutatorContext* mutator, uintptr_t* curs
842
890
}
843
891
}
844
892
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
+
845
906
STATIC_INLINE void * mmtk_immix_alloc_fast (MMTkMutatorContext * mutator , size_t size , size_t align , size_t offset ) {
846
907
ImmixAllocator * allocator = & mutator -> allocators .immix [MMTK_DEFAULT_IMMIX_ALLOCATOR ];
847
908
return bump_alloc_fast (mutator , (uintptr_t * )& allocator -> cursor , (intptr_t )allocator -> limit , size , align , offset , 0 );
848
909
}
849
910
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
-
854
911
STATIC_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
+ }
857
915
}
858
916
859
917
STATIC_INLINE void * mmtk_immortal_alloc_fast (MMTkMutatorContext * mutator , size_t size , size_t align , size_t offset ) {
860
918
BumpAllocator * allocator = & mutator -> allocators .bump_pointer [MMTK_IMMORTAL_BUMP_ALLOCATOR ];
861
919
return bump_alloc_fast (mutator , (uintptr_t * )& allocator -> cursor , (uintptr_t )allocator -> limit , size , align , offset , 1 );
862
920
}
863
921
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
+ }
868
930
}
869
931
870
932
JL_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
1042
1104
return jl_valueof (o );
1043
1105
}
1044
1106
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
+
1045
1117
JL_DLLEXPORT void * jl_gc_managed_malloc (size_t sz )
1046
1118
{
1047
1119
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)
1079
1151
mmtk_set_vm_space ((void * )img_data , len );
1080
1152
}
1081
1153
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
+
1082
1159
// ========================================================================= //
1083
1160
// Code specific to stock that is not supported by MMTk
1084
1161
// ========================================================================= //
@@ -1208,6 +1285,53 @@ JL_DLLEXPORT jl_value_t *jl_gc_internal_obj_base_ptr(void *p)
1208
1285
return NULL ;
1209
1286
}
1210
1287
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
+
1211
1335
#ifdef __cplusplus
1212
1336
}
1213
1337
#endif
0 commit comments