1 /* 2 * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2020, 2021, Red Hat, Inc. and/or its affiliates. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP 27 #define SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP 28 29 #include "gc/shared/referenceDiscoverer.hpp" 30 #include "gc/shared/referencePolicy.hpp" 31 #include "gc/shared/referenceProcessorStats.hpp" 32 #include "gc/shenandoah/shenandoahPhaseTimings.hpp" 33 #include "memory/allocation.hpp" 34 35 class ShenandoahMarkRefsSuperClosure; 36 class WorkerThreads; 37 38 static const size_t reference_type_count = REF_PHANTOM + 1; 39 typedef size_t Counters[reference_type_count]; 40 41 /* 42 * Shenandoah concurrent reference processing 43 * 44 * Concurrent reference processing is made up of two main phases: 45 * 1. Concurrent reference marking: Discover all j.l.r.Reference objects and determine reachability of all live objects. 46 * 2. Concurrent reference processing: For all discoved j.l.r.References, determine whether to keep them alive or clean 47 * them. Also, clean and enqueue relevant references concurrently. 48 * 49 * Concurrent reference marking: 50 * The goal here is to establish the kind of reachability for all objects on the heap. We distinguish two kinds of 51 * reachability: 52 * - An object is 'strongly reachable' if it can be found by searching transitively from GC roots. 53 * - An object is 'finalizably reachable' if it is not strongly reachable, but can be found by searching 54 * from the referents of FinalReferences. 55 * 56 * These reachabilities are implemented in shenandoahMarkBitMap.* 57 * Conceptually, marking starts with a strong wavefront at the GC roots. Whenever a Reference object is encountered, 58 * it may be discovered by the ShenandoahReferenceProcessor. If it is discovered, it 59 * gets added to the discovered list, and that wavefront stops there, except when it's a FinalReference, in which 60 * case the wavefront switches to finalizable marking and marks through the referent. When a Reference is not 61 * discovered, e.g. if it's a SoftReference that is not eligible for discovery, then marking continues as if the 62 * Reference was a regular object. Whenever a strong wavefront encounters an object that is already marked 63 * finalizable, then the object's reachability is upgraded to strong. 64 * 65 * Concurrent reference processing: 66 * This happens after the concurrent marking phase and the final marking pause, when reachability for all objects 67 * has been established. 68 * The discovered list is scanned and for each reference is decided what to do: 69 * - If the referent is reachable (finalizable for PhantomReference, strong for all others), then the Reference 70 * is dropped from the discovered list and otherwise ignored 71 * - Otherwise its referent becomes cleared and the Reference added to the pending list, from which it will later 72 * be processed (e.g. enqueued in its ReferenceQueue) by the Java ReferenceHandler thread. 73 * 74 * In order to prevent resurrection by Java threads calling Reference.get() concurrently while we are clearing 75 * referents, we employ a special barrier, the native LRB, which returns nullptr when the referent is unreachable. 76 */ 77 78 class ShenandoahRefProcThreadLocal : public CHeapObj<mtGC> { 79 private: 80 void* _discovered_list; 81 ShenandoahMarkRefsSuperClosure* _mark_closure; 82 Counters _encountered_count; 83 Counters _discovered_count; 84 Counters _enqueued_count; 85 NONCOPYABLE(ShenandoahRefProcThreadLocal); 86 87 public: 88 ShenandoahRefProcThreadLocal(); 89 90 void reset(); 91 92 ShenandoahMarkRefsSuperClosure* mark_closure() const { 93 return _mark_closure; 94 } 95 96 void set_mark_closure(ShenandoahMarkRefsSuperClosure* mark_closure) { 97 _mark_closure = mark_closure; 98 } 99 100 template<typename T> 101 T* discovered_list_addr(); 102 template<typename T> 103 oop discovered_list_head() const; 104 template<typename T> 105 void set_discovered_list_head(oop head); 106 107 size_t encountered(ReferenceType type) const { 108 return _encountered_count[type]; 109 } 110 size_t discovered(ReferenceType type) const { 111 return _discovered_count[type]; 112 } 113 size_t enqueued(ReferenceType type) const { 114 return _enqueued_count[type]; 115 } 116 117 void inc_encountered(ReferenceType type) { 118 _encountered_count[type]++; 119 } 120 void inc_discovered(ReferenceType type) { 121 _discovered_count[type]++; 122 } 123 void inc_enqueued(ReferenceType type) { 124 _enqueued_count[type]++; 125 } 126 }; 127 128 class ShenandoahReferenceProcessor : public ReferenceDiscoverer { 129 private: 130 ReferencePolicy* _soft_reference_policy; 131 132 ShenandoahRefProcThreadLocal* _ref_proc_thread_locals; 133 134 oop _pending_list; 135 void* _pending_list_tail; // T* 136 137 volatile uint _iterate_discovered_list_id; 138 139 ReferenceProcessorStats _stats; 140 141 template <typename T> 142 bool is_inactive(oop reference, oop referent, ReferenceType type) const; 143 bool is_strongly_live(oop referent) const; 144 bool is_softly_live(oop reference, ReferenceType type) const; 145 146 template <typename T> 147 bool should_discover(oop reference, ReferenceType type) const; 148 template <typename T> 149 bool should_drop(oop reference, ReferenceType type) const; 150 151 template <typename T> 152 void make_inactive(oop reference, ReferenceType type) const; 153 154 template <typename T> 155 bool discover(oop reference, ReferenceType type, uint worker_id); 156 157 template <typename T> 158 oop drop(oop reference, ReferenceType type); 159 template <typename T> 160 T* keep(oop reference, ReferenceType type, uint worker_id); 161 162 template <typename T> 163 void process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id); 164 void enqueue_references_locked(); 165 void enqueue_references(bool concurrent); 166 167 void collect_statistics(); 168 169 template<typename T> 170 void clean_discovered_list(T* list); 171 172 public: 173 ShenandoahReferenceProcessor(uint max_workers); 174 175 void reset_thread_locals(); 176 void set_mark_closure(uint worker_id, ShenandoahMarkRefsSuperClosure* mark_closure); 177 178 void set_soft_reference_policy(bool clear); 179 180 bool discover_reference(oop obj, ReferenceType type) override; 181 182 void process_references(ShenandoahPhaseTimings::Phase phase, WorkerThreads* workers, bool concurrent); 183 184 const ReferenceProcessorStats& reference_process_stats() { return _stats; } 185 186 void work(); 187 188 void abandon_partial_discovery(); 189 }; 190 191 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP