@@ -246,6 +246,24 @@ pub unsafe fn scan_julia_object<SV: SlotVisitor<JuliaVMSlot>>(obj: Address, clos
246246
247247 let ta = obj. to_ptr :: < jl_task_t > ( ) ;
248248
249+ #[ cfg( debug_assertions) ]
250+ {
251+ if !cfg ! ( feature = "non_moving" ) {
252+ // Panic if task has not been processed as root
253+ use crate :: scanning:: TASK_ROOTS ;
254+ let task_roots = TASK_ROOTS . lock ( ) . unwrap ( ) ;
255+
256+ let task_objref =
257+ ObjectReference :: from_raw_address_unchecked ( Address :: from_ptr ( ta) ) ;
258+ if !task_roots. contains ( & task_objref) {
259+ panic ! (
260+ "Task {} being scanned was not processed as root!" ,
261+ task_objref
262+ ) ;
263+ }
264+ }
265+ }
266+
249267 mmtk_scan_gcstack ( ta, closure, None ) ;
250268
251269 let layout = ( * jl_task_type) . layout ;
@@ -519,6 +537,123 @@ pub unsafe fn mmtk_scan_gcpreserve_stack<EV: SlotVisitor<JuliaVMSlot>>(
519537 }
520538}
521539
540+ // Scan the shadow stack for root tasks possibly capturing
541+ // more tasks that will also need to be scanned
542+ pub unsafe fn mmtk_scan_gcstack_roots < ' a , EV : SlotVisitor < JuliaVMSlot > > (
543+ ta : * const jl_task_t ,
544+ mut closure : & ' a mut EV ,
545+ mut pclosure : Option < & ' a mut EV > ,
546+ extra_root_tasks : & mut Vec < ObjectReference > ,
547+ ) {
548+ // process Julia's standard shadow (GC) stack
549+ let stkbuf = ( * ta) . ctx . stkbuf ;
550+ let copy_stack = ( * ta) . ctx . copy_stack_custom ( ) ;
551+
552+ #[ cfg( feature = "julia_copy_stack" ) ]
553+ if !stkbuf. is_null ( ) && copy_stack != 0 {
554+ let stkbuf_slot = Address :: from_ptr ( :: std:: ptr:: addr_of!( ( * ta) . ctx. stkbuf) ) ;
555+ process_slot ( closure, stkbuf_slot) ;
556+ }
557+
558+ let mut s = ( * ta) . gcstack ;
559+ let ( mut offset, mut lb, mut ub) = ( 0_isize , 0_u64 , u64:: MAX ) ;
560+
561+ #[ cfg( feature = "julia_copy_stack" ) ]
562+ if !stkbuf. is_null ( ) && copy_stack != 0 && ( * ta) . ptls . is_null ( ) {
563+ if ( ( * ta) . tid . _M_i ) < 0 {
564+ panic ! ( "tid must be positive." )
565+ }
566+ let stackbase = jl_gc_get_stackbase ( ( * ta) . tid . _M_i ) ;
567+ ub = stackbase as u64 ;
568+ lb = ub - ( ( * ta) . ctx . copy_stack ( ) as u64 ) ;
569+ offset = ( * ta) . ctx . stkbuf as isize - lb as isize ;
570+ }
571+
572+ if !s. is_null ( ) {
573+ let s_nroots_addr = :: std:: ptr:: addr_of!( ( * s) . nroots) ;
574+ let mut nroots = read_stack ( Address :: from_ptr ( s_nroots_addr) , offset, lb, ub) ;
575+ debug_assert ! ( nroots. as_usize( ) as u32 <= u32 :: MAX ) ;
576+ let mut nr = nroots >> 3 ;
577+
578+ loop {
579+ // if the 'pin' bit on the root type is not set, must transitively pin
580+ // and therefore use transitive pinning closure
581+ let closure_to_use: & mut & mut EV = if ( nroots. as_usize ( ) & 4 ) == 0 {
582+ & mut closure
583+ } else {
584+ // otherwise, use the pinning closure (if available)
585+ match & mut pclosure {
586+ Some ( c) => c,
587+ None => & mut closure,
588+ }
589+ } ;
590+
591+ let rts = Address :: from_mut_ptr ( s) . shift :: < Address > ( 2 ) ;
592+ let mut i = 0 ;
593+ while i < nr {
594+ if ( nroots. as_usize ( ) & 1 ) != 0 {
595+ let slot = read_stack ( rts. shift :: < Address > ( i as isize ) , offset, lb, ub) ;
596+ let real_addr = get_stack_addr ( slot, offset, lb, ub) ;
597+ process_slot ( * closure_to_use, real_addr) ;
598+ capture_potential_task ( real_addr, extra_root_tasks) ;
599+ } else {
600+ let real_addr =
601+ get_stack_addr ( rts. shift :: < Address > ( i as isize ) , offset, lb, ub) ;
602+
603+ let slot = read_stack ( rts. shift :: < Address > ( i as isize ) , offset, lb, ub) ;
604+ use crate :: julia_finalizer:: gc_ptr_tag;
605+ // malloced pointer tagged in jl_gc_add_quiescent
606+ // skip both the next element (native function), and the object
607+ if slot & 3usize == 3 {
608+ i += 2 ;
609+ continue ;
610+ }
611+
612+ // pointer is not malloced but function is native, so skip it
613+ if gc_ptr_tag ( slot, 1 ) {
614+ process_offset_slot ( * closure_to_use, real_addr, 1 ) ;
615+ i += 2 ;
616+ continue ;
617+ }
618+
619+ process_slot ( * closure_to_use, real_addr) ;
620+ capture_potential_task ( real_addr, extra_root_tasks) ;
621+ }
622+
623+ i += 1 ;
624+ }
625+
626+ let s_prev_address = :: std:: ptr:: addr_of!( ( * s) . prev) ;
627+ let sprev = read_stack ( Address :: from_ptr ( s_prev_address) , offset, lb, ub) ;
628+ if sprev. is_zero ( ) {
629+ break ;
630+ }
631+
632+ s = sprev. to_mut_ptr :: < jl_gcframe_t > ( ) ;
633+ let s_nroots_addr = :: std:: ptr:: addr_of!( ( * s) . nroots) ;
634+ let new_nroots = read_stack ( Address :: from_ptr ( s_nroots_addr) , offset, lb, ub) ;
635+ nroots = new_nroots;
636+ nr = nroots >> 3 ;
637+ continue ;
638+ }
639+ }
640+ }
641+
642+ pub unsafe fn capture_potential_task ( addr : Address , extra_root_tasks : & mut Vec < ObjectReference > ) {
643+ use mmtk:: vm:: slot:: Slot ;
644+ let simple_slot = SimpleSlot :: from_address ( addr) ;
645+
646+ if let Some ( objref) = simple_slot. load ( ) {
647+ let obj = objref. to_raw_address ( ) ;
648+ let vtag_usize = mmtk_jl_typetagof ( obj) . as_usize ( ) ;
649+
650+ if vtag_usize == ( ( jl_small_typeof_tags_jl_task_tag as usize ) << 4 ) {
651+ log:: info!( "Task {} occurs in shadow stack!" , objref) ;
652+ extra_root_tasks. push ( objref) ;
653+ }
654+ }
655+ }
656+
522657pub unsafe fn mmtk_scan_gcstack < ' a , EV : SlotVisitor < JuliaVMSlot > > (
523658 ta : * const jl_task_t ,
524659 mut closure : & ' a mut EV ,
0 commit comments