/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.mmtk.harness.vm; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.mmtk.harness.lang.Trace; import org.mmtk.harness.lang.Trace.Item; import org.mmtk.harness.lang.runtime.ReferenceValue; import org.mmtk.plan.TraceLocal; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.ObjectReference; /** * This class manages SoftReferences, WeakReferences, and * PhantomReferences. * * The harness only provides reference types to ensure that the MMTk * Plan processes them correctly, so all types have the semantics * of weak references. */ @Uninterruptible public final class ReferenceProcessor extends org.mmtk.vm.ReferenceProcessor { private static Map<Semantics,ReferenceProcessor> processors = new EnumMap<Semantics,ReferenceProcessor>(Semantics.class); static { processors.put(Semantics.SOFT, new ReferenceProcessor(Semantics.SOFT)); processors.put(Semantics.WEAK, new ReferenceProcessor(Semantics.WEAK)); processors.put(Semantics.PHANTOM, new ReferenceProcessor(Semantics.PHANTOM)); } static ReferenceProcessor getProcessorFor(Semantics semantics) { return processors.get(semantics); } /** * Discover a reference value while scanning stacks * @param ref Reference value */ public static void discover(ReferenceValue ref) { processors.get(ref.getSemantics()).add(ref); } /** * The set of reference objects of this semantics */ private final Set<ReferenceValue> oldRefs = new HashSet<ReferenceValue>(); private final Set<ReferenceValue> currentRefs = Collections.synchronizedSet(new HashSet<ReferenceValue>()); private final Set<ReferenceValue> newRefs = Collections.synchronizedSet(new HashSet<ReferenceValue>()); private final Semantics semantics; private ReferenceProcessor(Semantics semantics) { this.semantics = semantics; } /** * Add a reference value to the set of references of this type. * * This method is thread-safe, to support concurrent collection of * roots, by virtue of the synchronized collection types used for newRefs * and currentRefs. * * @param ref The reference value */ private void add(ReferenceValue ref) { Trace.trace(Item.REFERENCES, "Discovered reference %s", ref); if (!oldRefs.contains(ref)) { newRefs.add(ref); } else { currentRefs.add(ref); } } /** * Clear the contents of the table. This is called when reference types are * disabled to make it easier for VMs to change this setting at runtime. */ @Override public void clear() { Trace.trace(Item.REFERENCES, "Clearing %s references", semantics); currentRefs.clear(); newRefs.clear(); } /** * Scan through the list of references. * * TODO support concurrent scans * * TODO the nursery/mature logic could be improved * * @param trace the thread local trace element. * @param nursery true if it is safe to only scan new references. */ @Override public synchronized void scan(TraceLocal trace, boolean nursery) { Trace.trace(Item.REFERENCES, "Scanning %s references: current = %d, new = %d, %s", semantics,currentRefs.size(), newRefs.size(), nursery ? "nursery" : "full-heap"); if (!nursery) { scanReferenceSet(trace, currentRefs); } scanReferenceSet(trace, newRefs); oldRefs.clear(); oldRefs.addAll(currentRefs); oldRefs.addAll(newRefs); currentRefs.clear(); newRefs.clear(); } private void scanReferenceSet(TraceLocal trace, Set<ReferenceValue> set) { for (ReferenceValue value : set) { ObjectReference referent = value.getObjectValue(); if (trace.isReferentLive(referent)) { value.processReference(trace); } else { value.clear(); } } } /** * Iterate over all references and forward. Only relevant to collectors like * MarkCompact. * @param trace The MMTk trace to forward to * @param nursery The nursery collection hint */ @Override public void forward(TraceLocal trace, boolean nursery) { Trace.trace(Item.REFERENCES, "Forwarding %s references: %s", semantics,nursery ? "nursery" : "full-heap"); for (ReferenceValue value : oldRefs) { value.forwardReference(trace); } } /** * @return the number of references objects on the queue */ @Override public int countWaitingReferences() { return currentRefs.size() + newRefs.size(); } }