Skip to content

Commit 7a99b72

Browse files
authored
Fix root scanning (#165)
* Remove incorrect `MMTkRootScanWorkScope` * Optimize `CodeCache` roots scanning * Remove unused `compute_*_roots` functions
1 parent ebf6e74 commit 7a99b72

File tree

8 files changed

+131
-119
lines changed

8 files changed

+131
-119
lines changed

mmtk/src/api.rs

+50
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use mmtk::Mutator;
1515
use mmtk::MutatorContext;
1616
use mmtk::MMTK;
1717
use once_cell::sync;
18+
use std::cell::RefCell;
1819
use std::ffi::{CStr, CString};
20+
use std::sync::atomic::Ordering;
1921

2022
// Supported barriers:
2123
static NO_BARRIER: sync::Lazy<CString> = sync::Lazy::new(|| CString::new("NoBarrier").unwrap());
@@ -282,3 +284,51 @@ pub extern "C" fn get_finalized_object() -> ObjectReference {
282284
None => unsafe { Address::ZERO.to_object_reference() },
283285
}
284286
}
287+
288+
thread_local! {
289+
/// Cache all the pointers reported by the current thread.
290+
static NMETHOD_SLOTS: RefCell<Vec<Address>> = RefCell::new(vec![]);
291+
}
292+
293+
/// Report a list of pointers in nmethod to mmtk.
294+
#[no_mangle]
295+
pub extern "C" fn mmtk_add_nmethod_oop(addr: Address) {
296+
NMETHOD_SLOTS.with(|x| x.borrow_mut().push(addr))
297+
}
298+
299+
/// Register a nmethod.
300+
/// The c++ part of the binding should scan the nmethod and report all the pointers to mmtk first, before calling this function.
301+
/// This function will transfer all the locally cached pointers of this nmethod to the global storage.
302+
#[no_mangle]
303+
pub extern "C" fn mmtk_register_nmethod(nm: Address) {
304+
let slots = NMETHOD_SLOTS.with(|x| {
305+
if x.borrow().len() == 0 {
306+
return None;
307+
}
308+
Some(x.replace(vec![]))
309+
});
310+
let slots = match slots {
311+
Some(slots) => slots,
312+
_ => return,
313+
};
314+
let mut roots = crate::CODE_CACHE_ROOTS.lock().unwrap();
315+
// Relaxed add instead of `fetch_add`, since we've already acquired the lock.
316+
crate::CODE_CACHE_ROOTS_SIZE.store(
317+
crate::CODE_CACHE_ROOTS_SIZE.load(Ordering::Relaxed) + slots.len(),
318+
Ordering::Relaxed,
319+
);
320+
roots.insert(nm, slots);
321+
}
322+
323+
/// Unregister a nmethod.
324+
#[no_mangle]
325+
pub extern "C" fn mmtk_unregister_nmethod(nm: Address) {
326+
let mut roots = crate::CODE_CACHE_ROOTS.lock().unwrap();
327+
if let Some(slots) = roots.remove(&nm) {
328+
// Relaxed sub instead of `fetch_sub`, since we've already acquired the lock.
329+
crate::CODE_CACHE_ROOTS_SIZE.store(
330+
crate::CODE_CACHE_ROOTS_SIZE.load(Ordering::Relaxed) - slots.len(),
331+
Ordering::Relaxed,
332+
);
333+
}
334+
}

mmtk/src/gc_work.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::atomic::Ordering;
2+
13
use super::{OpenJDK, UPCALLS};
24
use mmtk::scheduler::*;
35
use mmtk::vm::RootsWorkFactory;
@@ -33,11 +35,38 @@ scan_roots_work!(ScanManagementRoots, scan_management_roots);
3335
scan_roots_work!(ScanJvmtiExportRoots, scan_jvmti_export_roots);
3436
scan_roots_work!(ScanAOTLoaderRoots, scan_aot_loader_roots);
3537
scan_roots_work!(ScanSystemDictionaryRoots, scan_system_dictionary_roots);
36-
scan_roots_work!(ScanCodeCacheRoots, scan_code_cache_roots);
3738
scan_roots_work!(ScanStringTableRoots, scan_string_table_roots);
3839
scan_roots_work!(
3940
ScanClassLoaderDataGraphRoots,
4041
scan_class_loader_data_graph_roots
4142
);
4243
scan_roots_work!(ScanWeakProcessorRoots, scan_weak_processor_roots);
4344
scan_roots_work!(ScanVMThreadRoots, scan_vm_thread_roots);
45+
46+
pub struct ScanCodeCacheRoots<F: RootsWorkFactory> {
47+
factory: F,
48+
}
49+
50+
impl<F: RootsWorkFactory> ScanCodeCacheRoots<F> {
51+
pub fn new(factory: F) -> Self {
52+
Self { factory }
53+
}
54+
}
55+
56+
impl<F: RootsWorkFactory> GCWork<OpenJDK> for ScanCodeCacheRoots<F> {
57+
fn do_work(&mut self, _worker: &mut GCWorker<OpenJDK>, _mmtk: &'static MMTK<OpenJDK>) {
58+
// Collect all the cached roots
59+
let mut edges = Vec::with_capacity(crate::CODE_CACHE_ROOTS_SIZE.load(Ordering::Relaxed));
60+
for roots in (*crate::CODE_CACHE_ROOTS.lock().unwrap()).values() {
61+
for r in roots {
62+
edges.push(*r)
63+
}
64+
}
65+
// Create work packet
66+
self.factory.create_process_edge_roots_work(edges);
67+
// Use the following code to scan CodeCache directly, instead of scanning the "remembered set".
68+
// unsafe {
69+
// ((*UPCALLS).scan_code_cache_roots)(create_process_edges_work::<E> as _);
70+
// }
71+
}
72+
}

mmtk/src/lib.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ extern crate mmtk;
44
extern crate lazy_static;
55
extern crate once_cell;
66

7+
use std::collections::HashMap;
78
use std::ptr::null_mut;
9+
use std::sync::atomic::AtomicUsize;
10+
use std::sync::Mutex;
811

912
use libc::{c_char, c_void, uintptr_t};
1013
use mmtk::util::alloc::AllocationError;
@@ -58,9 +61,6 @@ pub struct OpenJDK_Upcalls {
5861
pub out_of_memory: extern "C" fn(tls: VMThread, err_kind: AllocationError),
5962
pub get_next_mutator: extern "C" fn() -> *mut Mutator<OpenJDK>,
6063
pub reset_mutator_iterator: extern "C" fn(),
61-
pub compute_static_roots: extern "C" fn(trace: *mut c_void, tls: OpaquePointer),
62-
pub compute_global_roots: extern "C" fn(trace: *mut c_void, tls: OpaquePointer),
63-
pub compute_thread_roots: extern "C" fn(trace: *mut c_void, tls: OpaquePointer),
6464
pub scan_object: extern "C" fn(trace: *mut c_void, object: ObjectReference, tls: OpaquePointer),
6565
pub dump_object: extern "C" fn(object: ObjectReference),
6666
pub get_object_size: extern "C" fn(object: ObjectReference) -> usize,
@@ -74,8 +74,8 @@ pub struct OpenJDK_Upcalls {
7474
pub referent_offset: extern "C" fn() -> i32,
7575
pub discovered_offset: extern "C" fn() -> i32,
7676
pub dump_object_string: extern "C" fn(object: ObjectReference) -> *const c_char,
77-
pub scan_thread_roots: extern "C" fn(closure: EdgesClosure),
78-
pub scan_thread_root: extern "C" fn(closure: EdgesClosure, tls: VMMutatorThread),
77+
pub scan_all_thread_roots: extern "C" fn(closure: EdgesClosure),
78+
pub scan_thread_roots: extern "C" fn(closure: EdgesClosure, tls: VMMutatorThread),
7979
pub scan_universe_roots: extern "C" fn(closure: EdgesClosure),
8080
pub scan_jni_handle_roots: extern "C" fn(closure: EdgesClosure),
8181
pub scan_object_synchronizer_roots: extern "C" fn(closure: EdgesClosure),
@@ -142,3 +142,11 @@ lazy_static! {
142142
#[no_mangle]
143143
pub static MMTK_MARK_COMPACT_HEADER_RESERVED_IN_BYTES: usize =
144144
mmtk::util::alloc::MarkCompactAllocator::<OpenJDK>::HEADER_RESERVED_IN_BYTES;
145+
146+
lazy_static! {
147+
/// A global storage for all the cached CodeCache root pointers
148+
static ref CODE_CACHE_ROOTS: Mutex<HashMap<Address, Vec<Address>>> = Mutex::new(HashMap::new());
149+
}
150+
151+
/// A counter tracking the total size of the `CODE_CACHE_ROOTS`.
152+
static CODE_CACHE_ROOTS_SIZE: AtomicUsize = AtomicUsize::new(0);

mmtk/src/scanning.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl Scanning<OpenJDK> for VMScanning {
6060

6161
fn scan_thread_roots(_tls: VMWorkerThread, mut factory: impl RootsWorkFactory) {
6262
unsafe {
63-
((*UPCALLS).scan_thread_roots)(to_edges_closure(&mut factory));
63+
((*UPCALLS).scan_all_thread_roots)(to_edges_closure(&mut factory));
6464
}
6565
}
6666

@@ -71,7 +71,7 @@ impl Scanning<OpenJDK> for VMScanning {
7171
) {
7272
let tls = mutator.get_tls();
7373
unsafe {
74-
((*UPCALLS).scan_thread_root)(to_edges_closure(&mut factory), tls);
74+
((*UPCALLS).scan_thread_roots)(to_edges_closure(&mut factory), tls);
7575
}
7676
}
7777

openjdk/mmtk.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ extern void handle_user_collection_request(void *tls);
8787
extern void start_control_collector(void *tls, void *context);
8888
extern void start_worker(void *tls, void* worker);
8989

90+
extern size_t mmtk_add_nmethod_oop(void* object);
91+
extern size_t mmtk_register_nmethod(void* nm);
92+
extern size_t mmtk_unregister_nmethod(void* nm);
93+
9094
/**
9195
* VM Accounting
9296
*/
@@ -127,9 +131,6 @@ typedef struct {
127131
void (*out_of_memory) (void *tls, MMTkAllocationError err_kind);
128132
void* (*get_next_mutator) ();
129133
void (*reset_mutator_iterator) ();
130-
void (*compute_static_roots) (void* trace, void* tls);
131-
void (*compute_global_roots) (void* trace, void* tls);
132-
void (*compute_thread_roots) (void* trace, void* tls);
133134
void (*scan_object) (void* trace, void* object, void* tls);
134135
void (*dump_object) (void* object);
135136
size_t (*get_object_size) (void* object);
@@ -143,8 +144,8 @@ typedef struct {
143144
int (*referent_offset) ();
144145
int (*discovered_offset) ();
145146
char* (*dump_object_string) (void* object);
146-
void (*scan_thread_roots)(EdgesClosure closure);
147-
void (*scan_thread_root)(EdgesClosure closure, void* tls);
147+
void (*scan_all_thread_roots)(EdgesClosure closure);
148+
void (*scan_thread_roots)(EdgesClosure closure, void* tls);
148149
void (*scan_universe_roots) (EdgesClosure closure);
149150
void (*scan_jni_handle_roots) (EdgesClosure closure);
150151
void (*scan_object_synchronizer_roots) (EdgesClosure closure);

openjdk/mmtkHeap.cpp

+21-80
Original file line numberDiff line numberDiff line change
@@ -335,135 +335,76 @@ void MMTkHeap::print_tracing_info() const {
335335
}
336336

337337

338-
// An object is scavengable if its location may move during a scavenge.
339-
// (A scavenge is a GC which is not a full GC.)
340-
bool MMTkHeap::is_scavengable(oop obj) {return false;}
341338
// Registering and unregistering an nmethod (compiled code) with the heap.
342339
// Override with specific mechanism for each specialized heap type.
343-
344-
// Heap verification
345-
void MMTkHeap::verify(VerifyOption option) {}
346-
347-
template<int MAX_TASKS = 12>
348-
struct MMTkRootScanWorkScope {
349-
int* _num_root_scan_tasks;
350-
int _current_task_ordinal;
351-
MMTkRootScanWorkScope(int* num_root_scan_tasks): _num_root_scan_tasks(num_root_scan_tasks), _current_task_ordinal(0) {
352-
_current_task_ordinal = Atomic::add(1, _num_root_scan_tasks);
353-
if (_current_task_ordinal == 1) {
354-
nmethod::oops_do_marking_prologue();
355-
}
356-
}
357-
~MMTkRootScanWorkScope() {
358-
if (_current_task_ordinal == MAX_TASKS) {
359-
_current_task_ordinal = 0;
360-
nmethod::oops_do_marking_epilogue();
361-
}
340+
class MMTkRegisterNMethodOopClosure: public OopClosure {
341+
template <class T> void do_oop_work(T* p) {
342+
mmtk_add_nmethod_oop((void*) p);
362343
}
344+
public:
345+
void do_oop(oop* p) { do_oop_work(p); }
346+
void do_oop(narrowOop* p) { do_oop_work(p); }
363347
};
364348

365-
void MMTkHeap::scan_static_roots(OopClosure& cl) {
349+
350+
void MMTkHeap::register_nmethod(nmethod* nm) {
351+
// Scan and report pointers in this nmethod
352+
MMTkRegisterNMethodOopClosure reg_cl;
353+
nm->oops_do(&reg_cl);
354+
// Register the nmethod
355+
mmtk_register_nmethod((void*) nm);
366356
}
367357

358+
void MMTkHeap::unregister_nmethod(nmethod* nm) {
359+
mmtk_unregister_nmethod((void*) nm);
360+
}
361+
362+
// Heap verification
363+
void MMTkHeap::verify(VerifyOption option) {}
368364

369365
void MMTkHeap::scan_universe_roots(OopClosure& cl) {
370-
ResourceMark rm;
371-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
372366
Universe::oops_do(&cl);
373367
}
374368
void MMTkHeap::scan_jni_handle_roots(OopClosure& cl) {
375-
ResourceMark rm;
376-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
377369
JNIHandles::oops_do(&cl);
378370
}
379371
void MMTkHeap::scan_object_synchronizer_roots(OopClosure& cl) {
380-
ResourceMark rm;
381-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
382372
ObjectSynchronizer::oops_do(&cl);
383373
}
384374
void MMTkHeap::scan_management_roots(OopClosure& cl) {
385-
ResourceMark rm;
386-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
387375
Management::oops_do(&cl);
388376
}
389377
void MMTkHeap::scan_jvmti_export_roots(OopClosure& cl) {
390-
ResourceMark rm;
391-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
392378
JvmtiExport::oops_do(&cl);
393379
}
394380
void MMTkHeap::scan_aot_loader_roots(OopClosure& cl) {
395-
ResourceMark rm;
396-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
397381
AOTLoader::oops_do(&cl);
398382
}
399383
void MMTkHeap::scan_system_dictionary_roots(OopClosure& cl) {
400-
ResourceMark rm;
401-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
402384
SystemDictionary::oops_do(&cl);
403385
}
404386
void MMTkHeap::scan_code_cache_roots(OopClosure& cl) {
405-
ResourceMark rm;
406-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
407-
CodeBlobToOopClosure cb_cl(&cl, true);
408-
{
409-
MutexLockerEx lock(CodeCache_lock, Mutex::_no_safepoint_check_flag);
410-
CodeCache::scavenge_root_nmethods_do(&cb_cl);
411-
CodeCache::blobs_do(&cb_cl);
412-
}
387+
MarkingCodeBlobClosure cb_cl(&cl, false);
388+
CodeCache::blobs_do(&cb_cl);
413389
}
414390
void MMTkHeap::scan_string_table_roots(OopClosure& cl) {
415-
ResourceMark rm;
416-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
417391
StringTable::oops_do(&cl);
418392
}
419393
void MMTkHeap::scan_class_loader_data_graph_roots(OopClosure& cl) {
420-
ResourceMark rm;
421-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
422394
CLDToOopClosure cld_cl(&cl, false);
423395
ClassLoaderDataGraph::cld_do(&cld_cl);
424396
}
425397
void MMTkHeap::scan_weak_processor_roots(OopClosure& cl) {
426398
ResourceMark rm;
427-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
428399
WeakProcessor::oops_do(&cl); // (really needed???)
429400
}
430401
void MMTkHeap::scan_vm_thread_roots(OopClosure& cl) {
431402
ResourceMark rm;
432-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
433403
VMThread::vm_thread()->oops_do(&cl, NULL);
434404
}
435405

436-
void MMTkHeap::scan_global_roots(OopClosure& cl) {
437-
ResourceMark rm;
438-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
439-
440-
CodeBlobToOopClosure cb_cl(&cl, true);
441-
CLDToOopClosure cld_cl(&cl, false);
442-
443-
Universe::oops_do(&cl);
444-
JNIHandles::oops_do(&cl);
445-
ObjectSynchronizer::oops_do(&cl);
446-
Management::oops_do(&cl);
447-
JvmtiExport::oops_do(&cl);
448-
AOTLoader::oops_do(&cl);
449-
SystemDictionary::oops_do(&cl);
450-
{
451-
MutexLockerEx lock(CodeCache_lock, Mutex::_no_safepoint_check_flag);
452-
CodeCache::blobs_do(&cb_cl);
453-
}
454-
455-
OopStorage::ParState<false, false> _par_state_string(StringTable::weak_storage());
456-
StringTable::possibly_parallel_oops_do(&_par_state_string, &cl);
457-
458-
// if (!_root_tasks->is_task_claimed(MMTk_ClassLoaderDataGraph_oops_do)) ClassLoaderDataGraph::roots_cld_do(&cld_cl, &cld_cl);
459-
ClassLoaderDataGraph::cld_do(&cld_cl);
460-
461-
WeakProcessor::oops_do(&cl); // (really needed???)
462-
}
463-
464406
void MMTkHeap::scan_thread_roots(OopClosure& cl) {
465407
ResourceMark rm;
466-
MMTkRootScanWorkScope<> root_scan_work(&_num_root_scan_tasks);
467408
Threads::possibly_parallel_oops_do(false, &cl, NULL);
468409
}
469410

openjdk/mmtkHeap.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,11 @@ class MMTkHeap : public CollectedHeap {
181181

182182
// An object is scavengable if its location may move during a scavenge.
183183
// (A scavenge is a GC which is not a full GC.)
184-
bool is_scavengable(oop obj);
184+
inline bool is_scavengable(oop obj) { return true; }
185185
// Registering and unregistering an nmethod (compiled code) with the heap.
186186
// Override with specific mechanism for each specialized heap type.
187+
virtual void register_nmethod(nmethod* nm);
188+
virtual void unregister_nmethod(nmethod* nm);
187189

188190
// Heap verification
189191
void verify(VerifyOption option);
@@ -192,8 +194,6 @@ class MMTkHeap : public CollectedHeap {
192194

193195
void scan_roots(OopClosure& cl);
194196

195-
void scan_static_roots(OopClosure& cl);
196-
void scan_global_roots(OopClosure& cl);
197197
void scan_thread_roots(OopClosure& cl);
198198

199199
void scan_universe_roots(OopClosure& cl);

0 commit comments

Comments
 (0)