/* * 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.plan.refcount; import org.mmtk.plan.Phase; import org.mmtk.plan.Plan; import org.mmtk.plan.StopTheWorldCollector; import org.mmtk.plan.TraceLocal; import org.mmtk.plan.TransitiveClosure; import org.mmtk.plan.refcount.backuptrace.BTTraceLocal; import org.mmtk.policy.Space; import org.mmtk.policy.ExplicitFreeListSpace; import org.mmtk.utility.deque.ObjectReferenceDeque; import org.mmtk.vm.VM; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.ObjectReference; /** * This class implements the collector context for a reference counting collector. * See Shahriyar et al for details of and rationale for the optimizations used * here (http://dx.doi.org/10.1145/2258996.2259008). See Chapter 4 of * Daniel Frampton's PhD thesis for details of and rationale for the cycle * collection strategy used by this collector. */ @Uninterruptible public abstract class RCBaseCollector extends StopTheWorldCollector { /************************************************************************ * Initialization */ /** * */ protected final ObjectReferenceDeque newRootBuffer; private final BTTraceLocal backupTrace; private final ObjectReferenceDeque modBuffer; private final ObjectReferenceDeque oldRootBuffer; private final RCDecBuffer decBuffer; private final RCZero zero; /** * Constructor. */ public RCBaseCollector() { newRootBuffer = new ObjectReferenceDeque("new-root", global().newRootPool); oldRootBuffer = new ObjectReferenceDeque("old-root", global().oldRootPool); modBuffer = new ObjectReferenceDeque("mod buf", global().modPool); decBuffer = new RCDecBuffer(global().decPool); backupTrace = new BTTraceLocal(global().backupTrace); zero = new RCZero(); } /** * @return the modified processor to use. */ protected abstract TransitiveClosure getModifiedProcessor(); /** * @return the root trace to use. */ protected abstract TraceLocal getRootTrace(); /**************************************************************************** * * Collection */ /** * {@inheritDoc} */ @Override public void collect() { if (RCBase.BUILD_FOR_GENRC) Phase.beginNewPhaseStack(Phase.scheduleComplex(global().genRCCollection)); else Phase.beginNewPhaseStack(Phase.scheduleComplex(global().refCountCollection)); } @Override public void collectionPhase(short phaseId, boolean primary) { if (phaseId == RCBase.PREPARE) { getRootTrace().prepare(); if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) backupTrace.prepare(); return; } if (phaseId == RCBase.ROOTS) { VM.scanning.computeGlobalRoots(getCurrentTrace()); VM.scanning.computeStaticRoots(getCurrentTrace()); if (Plan.SCAN_BOOT_IMAGE && RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) { VM.scanning.computeBootImageRoots(getCurrentTrace()); } return; } if (phaseId == RCBase.CLOSURE) { getRootTrace().completeTrace(); newRootBuffer.flushLocal(); return; } if (phaseId == RCBase.BT_CLOSURE) { if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) { backupTrace.completeTrace(); } return; } if (phaseId == RCBase.PROCESS_OLDROOTBUFFER) { if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) return; ObjectReference current; while ((!(current = oldRootBuffer.pop()).isNull())) { decBuffer.push(current); } return; } if (phaseId == RCBase.PROCESS_NEWROOTBUFFER) { ObjectReference current; if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) { while (!(current = newRootBuffer.pop()).isNull()) { if (RCHeader.testAndMark(current)) { if (RCBase.BUILD_FOR_GENRC) { RCHeader.initRC(current); } else { if (RCHeader.initRC(current) == RCHeader.INC_NEW) { modBuffer.push(current); } } backupTrace.processNode(current); } else { if (RCBase.BUILD_FOR_GENRC) { RCHeader.incRC(current); } else { if (RCHeader.incRC(current) == RCHeader.INC_NEW) { modBuffer.push(current); } } } } if (!RCBase.BUILD_FOR_GENRC) modBuffer.flushLocal(); return; } while (!(current = newRootBuffer.pop()).isNull()) { if (RCBase.BUILD_FOR_GENRC) { RCHeader.incRC(current); } else { if (RCHeader.incRC(current) == RCHeader.INC_NEW) { modBuffer.push(current); } } oldRootBuffer.push(current); } oldRootBuffer.flushLocal(); if (!RCBase.BUILD_FOR_GENRC) modBuffer.flushLocal(); return; } if (phaseId == RCBase.PROCESS_MODBUFFER) { ObjectReference current; while (!(current = modBuffer.pop()).isNull()) { RCHeader.makeUnlogged(current); if (!RCBase.BUILD_FOR_GENRC) { if (Space.isInSpace(RCBase.REF_COUNT, current)) { ExplicitFreeListSpace.testAndSetLiveBit(current); } } VM.scanning.scanObject(getModifiedProcessor(), current); } return; } if (phaseId == RCBase.PROCESS_DECBUFFER) { ObjectReference current; if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) { if (!RCBase.BUILD_FOR_GENRC) { while (!(current = decBuffer.pop()).isNull()) { if (RCHeader.isNew(current)) { if (Space.isInSpace(RCBase.REF_COUNT, current)) { RCBase.rcSpace.free(current); } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) { RCBase.rcloSpace.free(current); } else if (Space.isInSpace(RCBase.IMMORTAL, current)) { VM.scanning.scanObject(zero, current); } } } } return; } while (!(current = decBuffer.pop()).isNull()) { if (RCBase.BUILD_FOR_GENRC) { if (RCHeader.decRC(current) == RCHeader.DEC_KILL) { decBuffer.processChildren(current); if (Space.isInSpace(RCBase.REF_COUNT, current)) { RCBase.rcSpace.free(current); } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) { RCBase.rcloSpace.free(current); } else if (Space.isInSpace(RCBase.IMMORTAL, current)) { VM.scanning.scanObject(zero, current); } } } else { if (RCHeader.isNew(current)) { if (Space.isInSpace(RCBase.REF_COUNT, current)) { RCBase.rcSpace.free(current); } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) { RCBase.rcloSpace.free(current); } else if (Space.isInSpace(RCBase.IMMORTAL, current)) { VM.scanning.scanObject(zero, current); } } else { if (RCHeader.decRC(current) == RCHeader.DEC_KILL) { decBuffer.processChildren(current); if (Space.isInSpace(RCBase.REF_COUNT, current)) { RCBase.rcSpace.free(current); } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) { RCBase.rcloSpace.free(current); } else if (Space.isInSpace(RCBase.IMMORTAL, current)) { VM.scanning.scanObject(zero, current); } } } } } return; } if (phaseId == RCBase.RELEASE) { if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) { backupTrace.release(); global().oldRootPool.clearDeque(1); if (RCBase.BUILD_FOR_GENRC) global().decPool.clearDeque(1); } getRootTrace().release(); if (VM.VERIFY_ASSERTIONS) { VM.assertions._assert(newRootBuffer.isEmpty()); VM.assertions._assert(modBuffer.isEmpty()); VM.assertions._assert(decBuffer.isEmpty()); } return; } super.collectionPhase(phaseId, primary); } /**************************************************************************** * * Miscellaneous */ /** @return The active global plan as an <code>RC</code> instance. */ @Inline protected static RCBase global() { return (RCBase) VM.activePlan.global(); } @Override public final TraceLocal getCurrentTrace() { return getRootTrace(); } /** @return The current modBuffer instance. */ @Inline public final ObjectReferenceDeque getModBuffer() { return modBuffer; } }