/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc_implementation/shared/gcTimer.hpp"
#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/referencePolicy.hpp"
#include "memory/referenceProcessor.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/jniHandles.hpp"
void referenceProcessor_init() {
}
// We need a monotonically non-deccreasing time in ms but
// os::javaTimeMillis() does not guarantee monotonicity.
// Initialize the soft ref timestamp clock.
// Also update the soft ref clock in j.l.r.SoftReference
vm_exit_during_initialization("Could not allocate reference policy object");
}
"Unrecongnized RefDiscoveryPolicy");
}
#ifdef ASSERT
// Verify that we're not currently discovering refs
if (check_no_refs) {
// Verify that the discovered lists are empty
}
#endif // ASSERT
// Someone could have modified the value of the static
// field in the j.l.r.SoftReference class that holds the
// soft reference timestamp clock using reflection or
// Unsafe between GCs. Unconditionally update the static
// field in ReferenceProcessor here so that we use the new
// value during reference discovery.
_discovering_refs = true;
}
bool mt_processing,
bool mt_discovery,
bool atomic_discovery,
bool discovered_list_needs_barrier) :
_discovering_refs(false),
_enqueuing_is_done(false),
_next_id(0)
{
if (_discovered_refs == NULL) {
vm_exit_during_initialization("Could not allocated RefProc Array");
}
// Initialize all entries to NULL
_discovered_refs[i].set_length(0);
}
// If we do barriers, cache a copy of the barrier set.
}
setup_policy(false /* default soft ref policy */);
}
#ifndef PRODUCT
"Found non-empty discovered list");
}
}
#endif
if (UseCompressedOops) {
} else {
}
}
}
// Update (advance) the soft ref master clock field. This must be done
// after processing the soft ref list.
// We need a monotonically non-deccreasing time in ms but
// os::javaTimeMillis() does not guarantee monotonicity.
if (now < _soft_ref_timestamp_clock) {
}
)
// The values of now and _soft_ref_timestamp_clock are set using
// javaTimeNanos(), which is guaranteed to be monotonically
// non-decreasing provided the underlying platform provides such
// a time source (and it is bug free).
// In product mode, however, protect ourselves from non-monotonicty.
if (now > _soft_ref_timestamp_clock) {
}
// Else leave clock stalled at its old value until time progresses
// past clock value.
}
for (uint i = 0; i < _max_num_q; ++i) {
}
return total;
}
// Stop treating discovered references specially.
// If discovery was concurrent, someone could have modified
// the value of the static field in the j.l.r.SoftReference
// class that holds the soft reference timestamp clock using
// reflection or Unsafe between when discovery was enabled and
// now. Unconditionally update the static field in ReferenceProcessor
// here so that we use the new value during processing of the
// discovered soft refs.
// Soft references
{
}
// Weak references
{
}
// Final references
{
}
// Phantom references
{
}
// Weak global JNI references. It would make more sense (semantically) to
// traverse these simultaneously with the regular weak references above, but
// that is not how the JDK1.2 specification is. See #4126360. Native code can
// thus use JNI weak references to circumvent the phantom references and
// resurrect a "post-mortem" object.
{
if (task_executor != NULL) {
}
}
}
#ifndef PRODUCT
// Calculate the number of jni handles.
public:
};
private:
int _count;
public:
};
return global_handle_count.count();
}
#endif
#ifndef PRODUCT
if (PrintGCDetails && PrintReferenceGC) {
}
#endif
complete_gc->do_void();
}
template <class T>
// Remember old value of pending references list
// Enqueue references that are not made active again, and
// clear the decks for the next collection (cycle).
// Do the oop-check on pending_list_addr missed in
// enqueue_discovered_reflist. We should probably
// do a raw oop_check so that future such idempotent
// oop_stores relying on the oop-check side-effect
// may be elided automatically and safely without
// affecting correctness.
// Stop treating discovered references specially.
ref->disable_discovery();
// Return true if new pending references were added
return old_pending_list_value != *pending_list_addr;
}
bool ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor) {
if (UseCompressedOops) {
} else {
}
}
// Given a list of refs linked through the "discovered" field
// (java.lang.ref.Reference.discovered), self-loop their "next" field
// thus distinguishing them from active References, then
// prepend them to the pending list.
// BKWRD COMPATIBILITY NOTE: For older JDKs (prior to the fix for 4956777),
// the "next" field is used to chain the pending list, not the discovered
// field.
if (TraceReferenceGC && PrintGCDetails) {
}
if (pending_list_uses_discovered_field()) { // New behaviour
// Walk down the list, self-looping the next field
// so that the References are not considered active.
if (TraceReferenceGC && PrintGCDetails) {
}
"Reference not active; should not be discovered");
// Self-loop next, so as to make Ref not active.
// Swap refs_list into pendling_list_addr and
// set obj's discovered to what we read from pending_list_addr.
// Need oop_check on pending_list_addr above;
// see special oop-check code at the end of
// enqueue_discovered_reflists() further below.
}
}
} else { // Old behaviour
// Walk down the list, copying the discovered field into
// the next field and clearing the discovered field.
if (TraceReferenceGC && PrintGCDetails) {
}
"The reference should not be enqueued");
// Swap refs_list into pendling_list_addr and
// set obj's next to what we read from pending_list_addr.
// Need oop_check on pending_list_addr above;
// see special oop-check code at the end of
// enqueue_discovered_reflists() further below.
// obj should be made to point to itself, since
// pending list was empty.
} else {
}
} else {
}
}
}
}
// Parallel enqueue task
public:
int n_queues)
{ }
// Simplest first cut: static partitioning.
// The increment on "index" must correspond to the maximum number of queues
// (n_queues) with which that ReferenceProcessor was created. That
// is because of the "clever" way the discovered references lists were
// allocated and are indexed into.
for (int j = 0;
}
}
};
// Enqueue references that are not made active again
// Parallel code
} else {
// Serial code: call the parent class's implementation
_discovered_refs[i].set_length(0);
}
}
}
"discovered field is bad");
_next = discovered;
"Wrong oop found in java.lang.Reference object");
"bad referent");
}
// First _prev_next ref actually points into DiscoveredList (gross).
// At the end of the list, we should make _prev point to itself.
// If _ref is the first ref, then _prev_next will be in the DiscoveredList,
// and _prev will be NULL.
} else {
}
if (UseCompressedOops) {
// Remove Reference object from list.
} else {
// Remove Reference object from list.
}
NOT_PRODUCT(_removed++);
}
// Make the Reference object active again.
// For G1 we don't want to use set_next - it
// will dirty the card for the next field of
// the reference object and will fail
// CT verification.
if (UseG1GC) {
if (UseCompressedOops) {
} else {
}
} else {
}
}
}
// NOTE: process_phase*() are largely similar, and at a high level
// merely iterate over the extant list applying a predicate to
// each of its elements and possibly removing that element from the
// list and applying some further closures to that element.
// We should consider the possibility of replacing these
// process_phase*() methods by abstracting them into
// a single general iterator invocation that receives appropriate
// closures that accomplish this work.
// (SoftReferences only) Traverse the list and remove any SoftReferences whose
// referents are not alive, but that should be kept alive for policy reasons.
// Keep alive the transitive closure of all such referents.
void
// Decide which softly reachable refs should be kept alive.
if (referent_is_dead &&
if (TraceReferenceGC) {
}
// Remove Reference object from list
// Make the Reference object active again
iter.make_active();
// keep the referent around
iter.move_to_next();
} else {
}
}
// Close the reachable set
complete_gc->do_void();
if (PrintGCDetails && TraceReferenceGC) {
"discovered Refs by policy, from list " INTPTR_FORMAT,
}
)
}
// Traverse the list and remove any Refs that are not active, or
// whose referents are either alive or NULL.
void
OopClosure* keep_alive) {
if (iter.is_referent_alive()) {
if (TraceReferenceGC) {
}
// The referent is reachable after all.
// Remove Reference object from list.
// Update the referent pointer as necessary: Note that this
// should not entail any recursive marking because the
// referent must already have been traversed.
iter.move_to_next();
} else {
}
}
"Refs in discovered list " INTPTR_FORMAT,
}
)
}
void
// Remove Reference object from list
// Trace the cohorts
if (UseCompressedOops) {
} else {
}
iter.move_to_next();
} else {
}
}
// Now close the newly reachable set
complete_gc->do_void();
"Refs in discovered list " INTPTR_FORMAT,
}
)
}
// Traverse the list and process the referents, by either
// clearing them or keeping them (and their reachable
// closure) alive.
void
bool clear_referent,
if (clear_referent) {
// NULL out referent pointer
} else {
// keep the referent around
}
if (TraceReferenceGC) {
}
}
// Remember to update the next pointer of the last ref.
// Close the reachable set
complete_gc->do_void();
}
void
}
refs_list.set_length(0);
}
void
}
// loop over the lists
}
}
}
public:
bool marks_oops_alive)
{ }
{
}
private:
};
public:
bool marks_oops_alive)
{ }
{
}
};
public:
bool clear_referent,
bool marks_oops_alive)
{ }
{
// Don't use "refs_list_index" calculated in this way because
// balance_queues() has moved the Ref's into the first n queues.
// Thread* thr = Thread::current();
// int refs_list_index = ((WorkerThread*)thr)->id();
// _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent,
}
private:
bool _clear_referent;
};
} else {
}
}
// Balances reference queues.
// Move entries from all queues[0, 1, ..., _max_num_q-1] to
// queues[0, 1, ..., _num_q-1] because only the first _num_q
// corresponding to the active workers will be processed.
{
// calculate total length
if (TraceReferenceGC && PrintGCDetails) {
}
for (uint i = 0; i < _max_num_q; ++i) {
if (TraceReferenceGC && PrintGCDetails) {
}
}
if (TraceReferenceGC && PrintGCDetails) {
}
bool move_all = false;
}
move_all) {
// move superfluous refs
// Move all the Ref's if the from queue will not be processed.
if (move_all) {
} else {
}
// find an element to split the list on
for (size_t j = 0; j < refs_to_move; ++j) {
}
// Add the chain to the to list.
// to list is empty. Make a loop at the end.
} else {
}
// Remove the chain from the from list.
// We found the end of the from list.
} else {
}
break;
}
} else {
}
}
}
#ifdef ASSERT
for (uint i = 0; i < _max_num_q; ++i) {
if (TraceReferenceGC && PrintGCDetails) {
}
}
if (TraceReferenceGC && PrintGCDetails) {
gclog_or_tty->flush();
}
#endif
}
}
bool clear_referent,
{
// If discovery used MT and a dynamic number of GC threads, then
// the queues must be balanced for correctness if fewer than the
// maximum number of queues were used. The number of queue used
// during discovery may be different than the number to be used
// for processing so don't depend of _num_q < _max_num_q as part
// of the test.
if ((mt_processing && ParallelRefProcBalancingEnabled) ||
must_balance) {
}
if (PrintReferenceGC && PrintGCDetails) {
}
// Phase 1 (soft refs only):
// . Traverse the list and remove any SoftReferences whose
// referents are not alive, but that should be kept alive for
// policy reasons. Keep alive the transitive closure of all
// such referents.
if (mt_processing) {
} else {
for (uint i = 0; i < _max_num_q; i++) {
}
}
} else { // policy == NULL
"Policy must be specified for soft references.");
}
// Phase 2:
// . Traverse the list and remove any refs whose referents are alive.
if (mt_processing) {
} else {
for (uint i = 0; i < _max_num_q; i++) {
}
}
// Phase 3:
// . Traverse the list and process referents as appropriate.
if (mt_processing) {
} else {
for (uint i = 0; i < _max_num_q; i++) {
}
}
return total_list_count;
}
// loop over the lists
"\nScrubbing %s discovered list of Null referents",
list_name(i));
}
}
}
// If referent has been cleared or Reference is not active,
// drop it.
if (PrintGCDetails && TraceReferenceGC) {
" and referent: " INTPTR_FORMAT,
}
)
// Remove Reference object from list
iter.move_to_next();
} else {
}
}
if (PrintGCDetails && TraceReferenceGC) {
" Removed %d Refs with NULL referents out of %d discovered Refs",
}
)
}
// Determine the queue index to use for this object.
if (_discovery_is_mt) {
// During a multi-threaded discovery phase,
// each thread saves to its "own" list.
} else {
// single-threaded discovery, we save in round-robin
// fashion to each of the lists.
if (_processing_is_mt) {
}
}
// Get the discovered queue to which we will add
switch (rt) {
case REF_OTHER:
// Unknown reference type, no special treatment
break;
case REF_SOFT:
break;
case REF_WEAK:
break;
case REF_FINAL:
break;
case REF_PHANTOM:
break;
case REF_NONE:
// we should not reach here if we are an instanceRefKlass
default:
}
if (TraceReferenceGC && PrintGCDetails) {
}
return list;
}
inline void
// First we must make sure this object is only enqueued once. CAS in a non null
// discovered_addr.
// The last ref must have its discovered field pointing to itself.
// Note: In the case of G1, this specific pre-barrier is strictly
// not necessary because the only case we are interested in
// here is when *discovered_addr is NULL (see the CAS further below),
// so this will expand to nothing. As a result, we have manually
// elided this out for G1, but left in the test for some future
// collector that might have need for a pre-barrier here, e.g.:-
// _bs->write_ref_field_pre((oop* or narrowOop*)discovered_addr, next_discovered);
"Need to check non-G1 collector: "
"may need a pre-write-barrier for CAS from NULL below");
NULL);
// This thread just won the right to enqueue the object.
// We have separate lists for enqueueing, so no synchronization
// is necessary.
}
if (TraceReferenceGC) {
}
} else {
// If retest was non NULL, another thread beat us to it:
// The reference has already been discovered...
if (TraceReferenceGC) {
}
}
}
#ifndef PRODUCT
// Non-atomic (i.e. concurrent) discovery might allow us
// to observe j.l.References with NULL referents, being those
// cleared concurrently by mutators during (or after) discovery.
INTPTR_FORMAT " during %satomic discovery ",
}
#endif
// We mention two of several possible choices here:
// #0: if the reference object is not in the "originating generation"
// (or part of the heap being collected, indicated by our "span"
// we don't treat it specially (i.e. we scan it as we would
// a normal oop, treating its references as strong references).
// This means that references can't be discovered unless their
// referent is also in the same span. This is the simplest,
// most "local" and most conservative approach, albeit one
// that may cause weak references to be enqueued least promptly.
// We call this choice the "ReferenceBasedDiscovery" policy.
// #1: the reference object may be in any generation (span), but if
// the referent is in the generation (span) being currently collected
// then we can discover the reference object, provided
// the object has not already been discovered by
// a different concurrently running collector (as may be the
// case, for instance, if the reference object is in CMS and
// the referent in DefNewGeneration), and provided the processing
// of this reference object by the current collector will
// appear atomic to every other collector in the system.
// (Thus, for instance, a concurrent collector may not
// discover references in other generations even if the
// referent is in its own generation). This policy may,
// in certain cases, enqueue references somewhat sooner than
// might Policy #0 above, but at marginally increased cost
// and complexity in processing these references.
// We call this choice the "RefeferentBasedDiscovery" policy.
// Make sure we are discovering refs (rather than processing discovered refs).
if (!_discovering_refs || !RegisterReferences) {
return false;
}
// We only discover active references.
return false;
}
if (RefDiscoveryPolicy == ReferenceBasedDiscovery &&
// Reference is not in the originating generation;
// don't treat it specially (i.e. we want to scan it as a normal
// object with strong references).
return false;
}
// We only discover references whose referents are not (yet)
// known to be strongly reachable.
if (is_alive_non_header() != NULL) {
return false; // referent is reachable
}
}
// For soft refs we can decide now if these are not
// current candidates for clearing, in which case we
// can mark through them now, rather than delaying that
// to the reference-processing phase. Since all current
// time-stamp policies advance the soft-ref clock only
// at a major collection cycle, this is always currently
// accurate.
return false;
}
}
if (discovered != NULL) {
// The reference has already been discovered...
if (TraceReferenceGC) {
}
if (RefDiscoveryPolicy == ReferentBasedDiscovery) {
// assumes that an object is not processed twice;
// if it's been already discovered it must be on another
// generation's discovered list; so we won't discover it.
return false;
} else {
"Unrecognized policy");
// Check assumption that an object is not potentially
// discovered twice except by concurrent collectors that potentially
// trace the same Reference object twice.
"Only possible with a concurrent marking collector");
return true;
}
}
if (RefDiscoveryPolicy == ReferentBasedDiscovery) {
// Discover if and only if EITHER:
// .. reference is in our span, OR
// .. we are an atomic collector and referent is in our span
(discovery_is_atomic() &&
// should_enqueue = true;
} else {
return false;
}
} else {
}
// Get the right type of discovered queue head.
return false; // nothing special needs to be done
}
if (_discovery_is_mt) {
} else {
// If "_discovered_list_needs_barrier", we do write barriers when
// updating the discovered reference list. Otherwise, we do a raw store
// here: the field will be visited later when processing the discovered
// references.
// The last ref must have its discovered field pointing to itself.
// As in the case further above, since we are over-writing a NULL
// pre-value, we can safely elide the pre-barrier here for the case of G1.
// e.g.:- _bs->write_ref_field_pre((oop* or narrowOop*)discovered_addr, next_discovered);
"For non-G1 collector, may need a pre-write-barrier for CAS from NULL below");
}
if (TraceReferenceGC) {
}
}
return true;
}
// Preclean the discovered references by removing those
// whose referents are alive, and by marking from those that
// are not active. These lists can be handled here
// in any order and, indeed, concurrently.
bool should_unload_classes,
#ifdef ASSERT
#endif
// Soft references
{
false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
}
}
// Weak references
{
false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
}
}
// Final references
{
false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
}
}
// Phantom references
{
false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
}
}
}
}
// Walk the given discovered ref list, and remove all reference objects
// whose referents are still alive, whose referents are NULL or which
// are not active (have a non-NULL next field). NOTE: When we are
// thus precleaning the ref lists (which happens single-threaded today),
// we do not disable refs discovery to honour the correct semantics of
// java.lang.Reference. As a result, we need to be careful below
// that ref removal steps interleave safely with ref discovery steps
// (in this thread).
void
YieldClosure* yield) {
// The referent has been cleared, or is alive, or the Reference is not
// active; we need to trace and mark its cohort.
if (TraceReferenceGC) {
}
// Remove Reference object from list
// Keep alive its cohort.
if (UseCompressedOops) {
} else {
}
iter.move_to_next();
} else {
}
}
// Close the reachable set
complete_gc->do_void();
"Refs in discovered list " INTPTR_FORMAT,
}
)
}
"Out of bounds index");
int j = i / _max_num_q;
switch (j) {
case 0: return "SoftRef";
case 1: return "WeakRef";
case 2: return "FinalRef";
case 3: return "PhantomRef";
}
return NULL;
}
#ifndef PRODUCT
// empty for now
}
#endif
#ifndef PRODUCT
}
}
#endif // PRODUCT