| 1 | /* |
| 2 | * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_GC_SHARED_REFERENCEPROCESSOR_HPP |
| 26 | #define SHARE_GC_SHARED_REFERENCEPROCESSOR_HPP |
| 27 | |
| 28 | #include "gc/shared/referenceDiscoverer.hpp" |
| 29 | #include "gc/shared/referencePolicy.hpp" |
| 30 | #include "gc/shared/referenceProcessorStats.hpp" |
| 31 | #include "memory/referenceType.hpp" |
| 32 | #include "oops/instanceRefKlass.hpp" |
| 33 | |
| 34 | class AbstractRefProcTaskExecutor; |
| 35 | class GCTimer; |
| 36 | class ReferencePolicy; |
| 37 | class ReferenceProcessorPhaseTimes; |
| 38 | |
| 39 | // List of discovered references. |
| 40 | class DiscoveredList { |
| 41 | public: |
| 42 | DiscoveredList() : _oop_head(NULL), _compressed_head(0), _len(0) { } |
| 43 | inline oop head() const; |
| 44 | HeapWord* adr_head() { |
| 45 | return UseCompressedOops ? (HeapWord*)&_compressed_head : |
| 46 | (HeapWord*)&_oop_head; |
| 47 | } |
| 48 | inline void set_head(oop o); |
| 49 | inline bool is_empty() const; |
| 50 | size_t length() { return _len; } |
| 51 | void set_length(size_t len) { _len = len; } |
| 52 | void inc_length(size_t inc) { _len += inc; assert(_len > 0, "Error" ); } |
| 53 | void dec_length(size_t dec) { _len -= dec; } |
| 54 | |
| 55 | inline void clear(); |
| 56 | private: |
| 57 | // Set value depending on UseCompressedOops. This could be a template class |
| 58 | // but then we have to fix all the instantiations and declarations that use this class. |
| 59 | oop _oop_head; |
| 60 | narrowOop _compressed_head; |
| 61 | size_t _len; |
| 62 | }; |
| 63 | |
| 64 | // Iterator for the list of discovered references. |
| 65 | class DiscoveredListIterator { |
| 66 | private: |
| 67 | DiscoveredList& _refs_list; |
| 68 | HeapWord* _prev_discovered_addr; |
| 69 | oop _prev_discovered; |
| 70 | oop _current_discovered; |
| 71 | HeapWord* _current_discovered_addr; |
| 72 | oop _next_discovered; |
| 73 | |
| 74 | HeapWord* _referent_addr; |
| 75 | oop _referent; |
| 76 | |
| 77 | OopClosure* _keep_alive; |
| 78 | BoolObjectClosure* _is_alive; |
| 79 | |
| 80 | DEBUG_ONLY( |
| 81 | oop _first_seen; // cyclic linked list check |
| 82 | ) |
| 83 | |
| 84 | size_t _processed; |
| 85 | size_t _removed; |
| 86 | |
| 87 | public: |
| 88 | inline DiscoveredListIterator(DiscoveredList& refs_list, |
| 89 | OopClosure* keep_alive, |
| 90 | BoolObjectClosure* is_alive); |
| 91 | |
| 92 | // End Of List. |
| 93 | inline bool has_next() const { return _current_discovered != NULL; } |
| 94 | |
| 95 | // Get oop to the Reference object. |
| 96 | inline oop obj() const { return _current_discovered; } |
| 97 | |
| 98 | // Get oop to the referent object. |
| 99 | inline oop referent() const { return _referent; } |
| 100 | |
| 101 | // Returns true if referent is alive. |
| 102 | inline bool is_referent_alive() const { |
| 103 | return _is_alive->do_object_b(_referent); |
| 104 | } |
| 105 | |
| 106 | // Loads data for the current reference. |
| 107 | // The "allow_null_referent" argument tells us to allow for the possibility |
| 108 | // of a NULL referent in the discovered Reference object. This typically |
| 109 | // happens in the case of concurrent collectors that may have done the |
| 110 | // discovery concurrently, or interleaved, with mutator execution. |
| 111 | void load_ptrs(DEBUG_ONLY(bool allow_null_referent)); |
| 112 | |
| 113 | // Move to the next discovered reference. |
| 114 | inline void next() { |
| 115 | _prev_discovered_addr = _current_discovered_addr; |
| 116 | _prev_discovered = _current_discovered; |
| 117 | move_to_next(); |
| 118 | } |
| 119 | |
| 120 | // Remove the current reference from the list |
| 121 | void remove(); |
| 122 | |
| 123 | // Make the referent alive. |
| 124 | inline void make_referent_alive() { |
| 125 | if (UseCompressedOops) { |
| 126 | _keep_alive->do_oop((narrowOop*)_referent_addr); |
| 127 | } else { |
| 128 | _keep_alive->do_oop((oop*)_referent_addr); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | // Do enqueuing work, i.e. notifying the GC about the changed discovered pointers. |
| 133 | void enqueue(); |
| 134 | |
| 135 | // Move enqueued references to the reference pending list. |
| 136 | void complete_enqueue(); |
| 137 | |
| 138 | // NULL out referent pointer. |
| 139 | void clear_referent(); |
| 140 | |
| 141 | // Statistics |
| 142 | inline size_t processed() const { return _processed; } |
| 143 | inline size_t removed() const { return _removed; } |
| 144 | |
| 145 | inline void move_to_next() { |
| 146 | if (oopDesc::equals_raw(_current_discovered, _next_discovered)) { |
| 147 | // End of the list. |
| 148 | _current_discovered = NULL; |
| 149 | } else { |
| 150 | _current_discovered = _next_discovered; |
| 151 | } |
| 152 | assert(!oopDesc::equals_raw(_current_discovered, _first_seen), "cyclic ref_list found" ); |
| 153 | _processed++; |
| 154 | } |
| 155 | }; |
| 156 | |
| 157 | // The ReferenceProcessor class encapsulates the per-"collector" processing |
| 158 | // of java.lang.Reference objects for GC. The interface is useful for supporting |
| 159 | // a generational abstraction, in particular when there are multiple |
| 160 | // generations that are being independently collected -- possibly |
| 161 | // concurrently and/or incrementally. |
| 162 | // ReferenceProcessor class abstracts away from a generational setting |
| 163 | // by using a closure that determines whether a given reference or referent are |
| 164 | // subject to this ReferenceProcessor's discovery, thus allowing its use in a |
| 165 | // straightforward manner in a general, non-generational, non-contiguous generation |
| 166 | // (or heap) setting. |
| 167 | class ReferenceProcessor : public ReferenceDiscoverer { |
| 168 | friend class RefProcPhase1Task; |
| 169 | friend class RefProcPhase2Task; |
| 170 | friend class RefProcPhase3Task; |
| 171 | friend class RefProcPhase4Task; |
| 172 | public: |
| 173 | // Names of sub-phases of reference processing. Indicates the type of the reference |
| 174 | // processed and the associated phase number at the end. |
| 175 | enum RefProcSubPhases { |
| 176 | SoftRefSubPhase1, |
| 177 | SoftRefSubPhase2, |
| 178 | WeakRefSubPhase2, |
| 179 | FinalRefSubPhase2, |
| 180 | FinalRefSubPhase3, |
| 181 | PhantomRefSubPhase4, |
| 182 | RefSubPhaseMax |
| 183 | }; |
| 184 | |
| 185 | // Main phases of reference processing. |
| 186 | enum RefProcPhases { |
| 187 | RefPhase1, |
| 188 | RefPhase2, |
| 189 | RefPhase3, |
| 190 | RefPhase4, |
| 191 | RefPhaseMax |
| 192 | }; |
| 193 | |
| 194 | private: |
| 195 | size_t total_count(DiscoveredList lists[]) const; |
| 196 | void verify_total_count_zero(DiscoveredList lists[], const char* type) NOT_DEBUG_RETURN; |
| 197 | |
| 198 | // The SoftReference master timestamp clock |
| 199 | static jlong _soft_ref_timestamp_clock; |
| 200 | |
| 201 | BoolObjectClosure* _is_subject_to_discovery; // determines whether a given oop is subject |
| 202 | // to this ReferenceProcessor's discovery |
| 203 | // (and further processing). |
| 204 | |
| 205 | bool _discovering_refs; // true when discovery enabled |
| 206 | bool _discovery_is_atomic; // if discovery is atomic wrt |
| 207 | // other collectors in configuration |
| 208 | bool _discovery_is_mt; // true if reference discovery is MT. |
| 209 | |
| 210 | bool _enqueuing_is_done; // true if all weak references enqueued |
| 211 | bool _processing_is_mt; // true during phases when |
| 212 | // reference processing is MT. |
| 213 | uint _next_id; // round-robin mod _num_queues counter in |
| 214 | // support of work distribution |
| 215 | |
| 216 | bool _adjust_no_of_processing_threads; // allow dynamic adjustment of processing threads |
| 217 | // For collectors that do not keep GC liveness information |
| 218 | // in the object header, this field holds a closure that |
| 219 | // helps the reference processor determine the reachability |
| 220 | // of an oop. It is currently initialized to NULL for all |
| 221 | // collectors except for CMS and G1. |
| 222 | BoolObjectClosure* ; |
| 223 | |
| 224 | // Soft ref clearing policies |
| 225 | // . the default policy |
| 226 | static ReferencePolicy* _default_soft_ref_policy; |
| 227 | // . the "clear all" policy |
| 228 | static ReferencePolicy* _always_clear_soft_ref_policy; |
| 229 | // . the current policy below is either one of the above |
| 230 | ReferencePolicy* _current_soft_ref_policy; |
| 231 | |
| 232 | // The discovered ref lists themselves |
| 233 | |
| 234 | // The active MT'ness degree of the queues below |
| 235 | uint _num_queues; |
| 236 | // The maximum MT'ness degree of the queues below |
| 237 | uint _max_num_queues; |
| 238 | |
| 239 | // Master array of discovered oops |
| 240 | DiscoveredList* _discovered_refs; |
| 241 | |
| 242 | // Arrays of lists of oops, one per thread (pointers into master array above) |
| 243 | DiscoveredList* _discoveredSoftRefs; |
| 244 | DiscoveredList* _discoveredWeakRefs; |
| 245 | DiscoveredList* _discoveredFinalRefs; |
| 246 | DiscoveredList* _discoveredPhantomRefs; |
| 247 | |
| 248 | // Phase 1: Re-evaluate soft ref policy. |
| 249 | void process_soft_ref_reconsider(BoolObjectClosure* is_alive, |
| 250 | OopClosure* keep_alive, |
| 251 | VoidClosure* complete_gc, |
| 252 | AbstractRefProcTaskExecutor* task_executor, |
| 253 | ReferenceProcessorPhaseTimes* phase_times); |
| 254 | |
| 255 | // Phase 2: Drop Soft/Weak/Final references with a NULL or live referent, and clear |
| 256 | // and enqueue non-Final references. |
| 257 | void process_soft_weak_final_refs(BoolObjectClosure* is_alive, |
| 258 | OopClosure* keep_alive, |
| 259 | VoidClosure* complete_gc, |
| 260 | AbstractRefProcTaskExecutor* task_executor, |
| 261 | ReferenceProcessorPhaseTimes* phase_times); |
| 262 | |
| 263 | // Phase 3: Keep alive followers of Final references, and enqueue. |
| 264 | void process_final_keep_alive(OopClosure* keep_alive, |
| 265 | VoidClosure* complete_gc, |
| 266 | AbstractRefProcTaskExecutor* task_executor, |
| 267 | ReferenceProcessorPhaseTimes* phase_times); |
| 268 | |
| 269 | // Phase 4: Drop and keep alive live Phantom references, or clear and enqueue if dead. |
| 270 | void process_phantom_refs(BoolObjectClosure* is_alive, |
| 271 | OopClosure* keep_alive, |
| 272 | VoidClosure* complete_gc, |
| 273 | AbstractRefProcTaskExecutor* task_executor, |
| 274 | ReferenceProcessorPhaseTimes* phase_times); |
| 275 | |
| 276 | // Work methods used by the process_* methods. All methods return the number of |
| 277 | // removed elements. |
| 278 | |
| 279 | // (SoftReferences only) Traverse the list and remove any SoftReferences whose |
| 280 | // referents are not alive, but that should be kept alive for policy reasons. |
| 281 | // Keep alive the transitive closure of all such referents. |
| 282 | size_t process_soft_ref_reconsider_work(DiscoveredList& refs_list, |
| 283 | ReferencePolicy* policy, |
| 284 | BoolObjectClosure* is_alive, |
| 285 | OopClosure* keep_alive, |
| 286 | VoidClosure* complete_gc); |
| 287 | |
| 288 | // Traverse the list and remove any Refs whose referents are alive, |
| 289 | // or NULL if discovery is not atomic. Enqueue and clear the reference for |
| 290 | // others if do_enqueue_and_clear is set. |
| 291 | size_t process_soft_weak_final_refs_work(DiscoveredList& refs_list, |
| 292 | BoolObjectClosure* is_alive, |
| 293 | OopClosure* keep_alive, |
| 294 | bool do_enqueue_and_clear); |
| 295 | |
| 296 | // Keep alive followers of referents for FinalReferences. Must only be called for |
| 297 | // those. |
| 298 | size_t process_final_keep_alive_work(DiscoveredList& refs_list, |
| 299 | OopClosure* keep_alive, |
| 300 | VoidClosure* complete_gc); |
| 301 | |
| 302 | size_t process_phantom_refs_work(DiscoveredList& refs_list, |
| 303 | BoolObjectClosure* is_alive, |
| 304 | OopClosure* keep_alive, |
| 305 | VoidClosure* complete_gc); |
| 306 | |
| 307 | public: |
| 308 | static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); } |
| 309 | |
| 310 | uint num_queues() const { return _num_queues; } |
| 311 | uint max_num_queues() const { return _max_num_queues; } |
| 312 | void set_active_mt_degree(uint v); |
| 313 | |
| 314 | ReferencePolicy* setup_policy(bool always_clear) { |
| 315 | _current_soft_ref_policy = always_clear ? |
| 316 | _always_clear_soft_ref_policy : _default_soft_ref_policy; |
| 317 | _current_soft_ref_policy->setup(); // snapshot the policy threshold |
| 318 | return _current_soft_ref_policy; |
| 319 | } |
| 320 | |
| 321 | // "Preclean" all the discovered reference lists by removing references that |
| 322 | // are active (e.g. due to the mutator calling enqueue()) or with NULL or |
| 323 | // strongly reachable referents. |
| 324 | // The first argument is a predicate on an oop that indicates |
| 325 | // its (strong) reachability and the fourth is a closure that |
| 326 | // may be used to incrementalize or abort the precleaning process. |
| 327 | // The caller is responsible for taking care of potential |
| 328 | // interference with concurrent operations on these lists |
| 329 | // (or predicates involved) by other threads. |
| 330 | void preclean_discovered_references(BoolObjectClosure* is_alive, |
| 331 | OopClosure* keep_alive, |
| 332 | VoidClosure* complete_gc, |
| 333 | YieldClosure* yield, |
| 334 | GCTimer* gc_timer); |
| 335 | |
| 336 | private: |
| 337 | // Returns the name of the discovered reference list |
| 338 | // occupying the i / _num_queues slot. |
| 339 | const char* list_name(uint i); |
| 340 | |
| 341 | // "Preclean" the given discovered reference list by removing references with |
| 342 | // the attributes mentioned in preclean_discovered_references(). |
| 343 | // Supports both normal and fine grain yielding. |
| 344 | // Returns whether the operation should be aborted. |
| 345 | bool preclean_discovered_reflist(DiscoveredList& refs_list, |
| 346 | BoolObjectClosure* is_alive, |
| 347 | OopClosure* keep_alive, |
| 348 | VoidClosure* complete_gc, |
| 349 | YieldClosure* yield); |
| 350 | |
| 351 | // round-robin mod _num_queues (not: _not_ mod _max_num_queues) |
| 352 | uint next_id() { |
| 353 | uint id = _next_id; |
| 354 | assert(!_discovery_is_mt, "Round robin should only be used in serial discovery" ); |
| 355 | if (++_next_id == _num_queues) { |
| 356 | _next_id = 0; |
| 357 | } |
| 358 | assert(_next_id < _num_queues, "_next_id %u _num_queues %u _max_num_queues %u" , _next_id, _num_queues, _max_num_queues); |
| 359 | return id; |
| 360 | } |
| 361 | DiscoveredList* get_discovered_list(ReferenceType rt); |
| 362 | inline void add_to_discovered_list_mt(DiscoveredList& refs_list, oop obj, |
| 363 | HeapWord* discovered_addr); |
| 364 | |
| 365 | void clear_discovered_references(DiscoveredList& refs_list); |
| 366 | |
| 367 | void log_reflist(const char* prefix, DiscoveredList list[], uint num_active_queues); |
| 368 | void log_reflist_counts(DiscoveredList ref_lists[], uint num_active_queues) PRODUCT_RETURN; |
| 369 | |
| 370 | // Balances reference queues. |
| 371 | void balance_queues(DiscoveredList refs_lists[]); |
| 372 | bool need_balance_queues(DiscoveredList refs_lists[]); |
| 373 | |
| 374 | // If there is need to balance the given queue, do it. |
| 375 | void maybe_balance_queues(DiscoveredList refs_lists[]); |
| 376 | |
| 377 | // Update (advance) the soft ref master clock field. |
| 378 | void update_soft_ref_master_clock(); |
| 379 | |
| 380 | bool is_subject_to_discovery(oop const obj) const; |
| 381 | |
| 382 | bool is_mt_processing_set_up(AbstractRefProcTaskExecutor* task_executor) const; |
| 383 | |
| 384 | public: |
| 385 | // Default parameters give you a vanilla reference processor. |
| 386 | ReferenceProcessor(BoolObjectClosure* is_subject_to_discovery, |
| 387 | bool mt_processing = false, uint mt_processing_degree = 1, |
| 388 | bool mt_discovery = false, uint mt_discovery_degree = 1, |
| 389 | bool atomic_discovery = true, |
| 390 | BoolObjectClosure* = NULL, |
| 391 | bool adjust_no_of_processing_threads = false); |
| 392 | |
| 393 | // RefDiscoveryPolicy values |
| 394 | enum DiscoveryPolicy { |
| 395 | ReferenceBasedDiscovery = 0, |
| 396 | ReferentBasedDiscovery = 1, |
| 397 | DiscoveryPolicyMin = ReferenceBasedDiscovery, |
| 398 | DiscoveryPolicyMax = ReferentBasedDiscovery |
| 399 | }; |
| 400 | |
| 401 | static void init_statics(); |
| 402 | |
| 403 | // get and set "is_alive_non_header" field |
| 404 | BoolObjectClosure* () { |
| 405 | return _is_alive_non_header; |
| 406 | } |
| 407 | void (BoolObjectClosure* ) { |
| 408 | _is_alive_non_header = is_alive_non_header; |
| 409 | } |
| 410 | |
| 411 | BoolObjectClosure* is_subject_to_discovery_closure() const { return _is_subject_to_discovery; } |
| 412 | void set_is_subject_to_discovery_closure(BoolObjectClosure* cl) { _is_subject_to_discovery = cl; } |
| 413 | |
| 414 | // start and stop weak ref discovery |
| 415 | void enable_discovery(bool check_no_refs = true); |
| 416 | void disable_discovery() { _discovering_refs = false; } |
| 417 | bool discovery_enabled() { return _discovering_refs; } |
| 418 | |
| 419 | // whether discovery is atomic wrt other collectors |
| 420 | bool discovery_is_atomic() const { return _discovery_is_atomic; } |
| 421 | void set_atomic_discovery(bool atomic) { _discovery_is_atomic = atomic; } |
| 422 | |
| 423 | // whether discovery is done by multiple threads same-old-timeously |
| 424 | bool discovery_is_mt() const { return _discovery_is_mt; } |
| 425 | void set_mt_discovery(bool mt) { _discovery_is_mt = mt; } |
| 426 | |
| 427 | // Whether we are in a phase when _processing_ is MT. |
| 428 | bool processing_is_mt() const { return _processing_is_mt; } |
| 429 | void set_mt_processing(bool mt) { _processing_is_mt = mt; } |
| 430 | |
| 431 | // whether all enqueueing of weak references is complete |
| 432 | bool enqueuing_is_done() { return _enqueuing_is_done; } |
| 433 | void set_enqueuing_is_done(bool v) { _enqueuing_is_done = v; } |
| 434 | |
| 435 | // iterate over oops |
| 436 | void weak_oops_do(OopClosure* f); // weak roots |
| 437 | |
| 438 | void verify_list(DiscoveredList& ref_list); |
| 439 | |
| 440 | // Discover a Reference object, using appropriate discovery criteria |
| 441 | virtual bool discover_reference(oop obj, ReferenceType rt); |
| 442 | |
| 443 | // Has discovered references that need handling |
| 444 | bool has_discovered_references(); |
| 445 | |
| 446 | // Process references found during GC (called by the garbage collector) |
| 447 | ReferenceProcessorStats |
| 448 | process_discovered_references(BoolObjectClosure* is_alive, |
| 449 | OopClosure* keep_alive, |
| 450 | VoidClosure* complete_gc, |
| 451 | AbstractRefProcTaskExecutor* task_executor, |
| 452 | ReferenceProcessorPhaseTimes* phase_times); |
| 453 | |
| 454 | // If a discovery is in process that is being superceded, abandon it: all |
| 455 | // the discovered lists will be empty, and all the objects on them will |
| 456 | // have NULL discovered fields. Must be called only at a safepoint. |
| 457 | void abandon_partial_discovery(); |
| 458 | |
| 459 | size_t total_reference_count(ReferenceType rt) const; |
| 460 | |
| 461 | // debugging |
| 462 | void verify_no_references_recorded() PRODUCT_RETURN; |
| 463 | void verify_referent(oop obj) PRODUCT_RETURN; |
| 464 | |
| 465 | bool adjust_no_of_processing_threads() const { return _adjust_no_of_processing_threads; } |
| 466 | }; |
| 467 | |
| 468 | // A subject-to-discovery closure that uses a single memory span to determine the area that |
| 469 | // is subject to discovery. Useful for collectors which have contiguous generations. |
| 470 | class SpanSubjectToDiscoveryClosure : public BoolObjectClosure { |
| 471 | MemRegion _span; |
| 472 | |
| 473 | public: |
| 474 | SpanSubjectToDiscoveryClosure() : BoolObjectClosure(), _span() { } |
| 475 | SpanSubjectToDiscoveryClosure(MemRegion span) : BoolObjectClosure(), _span(span) { } |
| 476 | |
| 477 | MemRegion span() const { return _span; } |
| 478 | |
| 479 | void set_span(MemRegion mr) { |
| 480 | _span = mr; |
| 481 | } |
| 482 | |
| 483 | virtual bool do_object_b(oop obj) { |
| 484 | return _span.contains(obj); |
| 485 | } |
| 486 | }; |
| 487 | |
| 488 | // A utility class to disable reference discovery in |
| 489 | // the scope which contains it, for given ReferenceProcessor. |
| 490 | class NoRefDiscovery: StackObj { |
| 491 | private: |
| 492 | ReferenceProcessor* _rp; |
| 493 | bool _was_discovering_refs; |
| 494 | public: |
| 495 | NoRefDiscovery(ReferenceProcessor* rp) : _rp(rp) { |
| 496 | _was_discovering_refs = _rp->discovery_enabled(); |
| 497 | if (_was_discovering_refs) { |
| 498 | _rp->disable_discovery(); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | ~NoRefDiscovery() { |
| 503 | if (_was_discovering_refs) { |
| 504 | _rp->enable_discovery(false /*check_no_refs*/); |
| 505 | } |
| 506 | } |
| 507 | }; |
| 508 | |
| 509 | // A utility class to temporarily mutate the subject discovery closure of the |
| 510 | // given ReferenceProcessor in the scope that contains it. |
| 511 | class ReferenceProcessorSubjectToDiscoveryMutator : StackObj { |
| 512 | ReferenceProcessor* _rp; |
| 513 | BoolObjectClosure* _saved_cl; |
| 514 | |
| 515 | public: |
| 516 | ReferenceProcessorSubjectToDiscoveryMutator(ReferenceProcessor* rp, BoolObjectClosure* cl): |
| 517 | _rp(rp) { |
| 518 | _saved_cl = _rp->is_subject_to_discovery_closure(); |
| 519 | _rp->set_is_subject_to_discovery_closure(cl); |
| 520 | } |
| 521 | |
| 522 | ~ReferenceProcessorSubjectToDiscoveryMutator() { |
| 523 | _rp->set_is_subject_to_discovery_closure(_saved_cl); |
| 524 | } |
| 525 | }; |
| 526 | |
| 527 | // A utility class to temporarily mutate the span of the |
| 528 | // given ReferenceProcessor in the scope that contains it. |
| 529 | class ReferenceProcessorSpanMutator : StackObj { |
| 530 | ReferenceProcessor* _rp; |
| 531 | SpanSubjectToDiscoveryClosure _discoverer; |
| 532 | BoolObjectClosure* _old_discoverer; |
| 533 | |
| 534 | public: |
| 535 | ReferenceProcessorSpanMutator(ReferenceProcessor* rp, |
| 536 | MemRegion span): |
| 537 | _rp(rp), |
| 538 | _discoverer(span), |
| 539 | _old_discoverer(rp->is_subject_to_discovery_closure()) { |
| 540 | |
| 541 | rp->set_is_subject_to_discovery_closure(&_discoverer); |
| 542 | } |
| 543 | |
| 544 | ~ReferenceProcessorSpanMutator() { |
| 545 | _rp->set_is_subject_to_discovery_closure(_old_discoverer); |
| 546 | } |
| 547 | }; |
| 548 | |
| 549 | // A utility class to temporarily change the MT'ness of |
| 550 | // reference discovery for the given ReferenceProcessor |
| 551 | // in the scope that contains it. |
| 552 | class ReferenceProcessorMTDiscoveryMutator: StackObj { |
| 553 | private: |
| 554 | ReferenceProcessor* _rp; |
| 555 | bool _saved_mt; |
| 556 | |
| 557 | public: |
| 558 | ReferenceProcessorMTDiscoveryMutator(ReferenceProcessor* rp, |
| 559 | bool mt): |
| 560 | _rp(rp) { |
| 561 | _saved_mt = _rp->discovery_is_mt(); |
| 562 | _rp->set_mt_discovery(mt); |
| 563 | } |
| 564 | |
| 565 | ~ReferenceProcessorMTDiscoveryMutator() { |
| 566 | _rp->set_mt_discovery(_saved_mt); |
| 567 | } |
| 568 | }; |
| 569 | |
| 570 | // A utility class to temporarily change the disposition |
| 571 | // of the "is_alive_non_header" closure field of the |
| 572 | // given ReferenceProcessor in the scope that contains it. |
| 573 | class ReferenceProcessorIsAliveMutator: StackObj { |
| 574 | private: |
| 575 | ReferenceProcessor* _rp; |
| 576 | BoolObjectClosure* _saved_cl; |
| 577 | |
| 578 | public: |
| 579 | ReferenceProcessorIsAliveMutator(ReferenceProcessor* rp, |
| 580 | BoolObjectClosure* cl): |
| 581 | _rp(rp) { |
| 582 | _saved_cl = _rp->is_alive_non_header(); |
| 583 | _rp->set_is_alive_non_header(cl); |
| 584 | } |
| 585 | |
| 586 | ~ReferenceProcessorIsAliveMutator() { |
| 587 | _rp->set_is_alive_non_header(_saved_cl); |
| 588 | } |
| 589 | }; |
| 590 | |
| 591 | // A utility class to temporarily change the disposition |
| 592 | // of the "discovery_is_atomic" field of the |
| 593 | // given ReferenceProcessor in the scope that contains it. |
| 594 | class ReferenceProcessorAtomicMutator: StackObj { |
| 595 | private: |
| 596 | ReferenceProcessor* _rp; |
| 597 | bool _saved_atomic_discovery; |
| 598 | |
| 599 | public: |
| 600 | ReferenceProcessorAtomicMutator(ReferenceProcessor* rp, |
| 601 | bool atomic): |
| 602 | _rp(rp) { |
| 603 | _saved_atomic_discovery = _rp->discovery_is_atomic(); |
| 604 | _rp->set_atomic_discovery(atomic); |
| 605 | } |
| 606 | |
| 607 | ~ReferenceProcessorAtomicMutator() { |
| 608 | _rp->set_atomic_discovery(_saved_atomic_discovery); |
| 609 | } |
| 610 | }; |
| 611 | |
| 612 | |
| 613 | // A utility class to temporarily change the MT processing |
| 614 | // disposition of the given ReferenceProcessor instance |
| 615 | // in the scope that contains it. |
| 616 | class ReferenceProcessorMTProcMutator: StackObj { |
| 617 | private: |
| 618 | ReferenceProcessor* _rp; |
| 619 | bool _saved_mt; |
| 620 | |
| 621 | public: |
| 622 | ReferenceProcessorMTProcMutator(ReferenceProcessor* rp, |
| 623 | bool mt): |
| 624 | _rp(rp) { |
| 625 | _saved_mt = _rp->processing_is_mt(); |
| 626 | _rp->set_mt_processing(mt); |
| 627 | } |
| 628 | |
| 629 | ~ReferenceProcessorMTProcMutator() { |
| 630 | _rp->set_mt_processing(_saved_mt); |
| 631 | } |
| 632 | }; |
| 633 | |
| 634 | // This class is an interface used to implement task execution for the |
| 635 | // reference processing. |
| 636 | class AbstractRefProcTaskExecutor { |
| 637 | public: |
| 638 | |
| 639 | // Abstract tasks to execute. |
| 640 | class ProcessTask; |
| 641 | |
| 642 | // Executes a task using worker threads. |
| 643 | virtual void execute(ProcessTask& task, uint ergo_workers) = 0; |
| 644 | |
| 645 | // Switch to single threaded mode. |
| 646 | virtual void set_single_threaded_mode() { }; |
| 647 | }; |
| 648 | |
| 649 | // Abstract reference processing task to execute. |
| 650 | class AbstractRefProcTaskExecutor::ProcessTask { |
| 651 | protected: |
| 652 | ReferenceProcessor& _ref_processor; |
| 653 | // Indicates whether the phase could generate work that should be balanced across |
| 654 | // threads after execution. |
| 655 | bool _marks_oops_alive; |
| 656 | ReferenceProcessorPhaseTimes* _phase_times; |
| 657 | |
| 658 | ProcessTask(ReferenceProcessor& ref_processor, |
| 659 | bool marks_oops_alive, |
| 660 | ReferenceProcessorPhaseTimes* phase_times) |
| 661 | : _ref_processor(ref_processor), |
| 662 | _marks_oops_alive(marks_oops_alive), |
| 663 | _phase_times(phase_times) |
| 664 | { } |
| 665 | |
| 666 | public: |
| 667 | virtual void work(uint worker_id, |
| 668 | BoolObjectClosure& is_alive, |
| 669 | OopClosure& keep_alive, |
| 670 | VoidClosure& complete_gc) = 0; |
| 671 | |
| 672 | bool marks_oops_alive() const { return _marks_oops_alive; } |
| 673 | }; |
| 674 | |
| 675 | // Temporarily change the number of workers based on given reference count. |
| 676 | // This ergonomically decided worker count will be used to activate worker threads. |
| 677 | class RefProcMTDegreeAdjuster : public StackObj { |
| 678 | typedef ReferenceProcessor::RefProcPhases RefProcPhases; |
| 679 | |
| 680 | ReferenceProcessor* _rp; |
| 681 | bool _saved_mt_processing; |
| 682 | uint _saved_num_queues; |
| 683 | |
| 684 | // Calculate based on total of references. |
| 685 | uint ergo_proc_thread_count(size_t ref_count, |
| 686 | uint max_threads, |
| 687 | RefProcPhases phase) const; |
| 688 | |
| 689 | bool use_max_threads(RefProcPhases phase) const; |
| 690 | |
| 691 | public: |
| 692 | RefProcMTDegreeAdjuster(ReferenceProcessor* rp, |
| 693 | RefProcPhases phase, |
| 694 | size_t ref_count); |
| 695 | ~RefProcMTDegreeAdjuster(); |
| 696 | }; |
| 697 | |
| 698 | #endif // SHARE_GC_SHARED_REFERENCEPROCESSOR_HPP |
| 699 | |