| /* |
| * 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.StopTheWorld; |
| import org.mmtk.plan.Trace; |
| import org.mmtk.plan.refcount.backuptrace.BTFreeLargeObjectSweeper; |
| import org.mmtk.plan.refcount.backuptrace.BTScanLargeObjectSweeper; |
| import org.mmtk.plan.refcount.backuptrace.BTSweeper; |
| import org.mmtk.policy.ExplicitFreeListSpace; |
| import org.mmtk.policy.ExplicitLargeObjectSpace; |
| import org.mmtk.policy.Space; |
| import org.mmtk.utility.Log; |
| import org.mmtk.utility.alloc.LinearScan; |
| import org.mmtk.utility.deque.SharedDeque; |
| import org.mmtk.utility.heap.VMRequest; |
| import org.mmtk.utility.options.Options; |
| import org.mmtk.utility.sanitychecker.SanityChecker; |
| import org.mmtk.vm.VM; |
| |
| import org.vmmagic.pragma.*; |
| import org.vmmagic.unboxed.ObjectReference; |
| |
| /** |
| * This class implements the global state of a a simple reference counting collector. |
| */ |
| @Uninterruptible |
| public class RCBase extends StopTheWorld { |
| public static final short PROCESS_OLDROOTBUFFER = Phase.createSimple("old-root"); |
| public static final short PROCESS_NEWROOTBUFFER = Phase.createSimple("new-root"); |
| public static final short PROCESS_MODBUFFER = Phase.createSimple("mods"); |
| public static final short PROCESS_DECBUFFER = Phase.createSimple("decs"); |
| |
| /** Is cycle collection enabled? */ |
| public static final boolean CC_ENABLED = true; |
| /** Force full cycle collection at each GC? */ |
| public static final boolean CC_FORCE_FULL = false; |
| /** Use backup tracing for cycle collection (currently the only option) */ |
| public static final boolean CC_BACKUP_TRACE = true; |
| |
| public static boolean performCycleCollection; |
| public static final short BT_CLOSURE = Phase.createSimple("closure-bt"); |
| |
| // CHECKSTYLE:OFF |
| |
| /** |
| * Reference counting specific collection steps. |
| */ |
| protected static final short refCountCollectionPhase = Phase.createComplex("release", null, |
| Phase.scheduleGlobal (PROCESS_OLDROOTBUFFER), |
| Phase.scheduleCollector (PROCESS_OLDROOTBUFFER), |
| Phase.scheduleGlobal (PROCESS_NEWROOTBUFFER), |
| Phase.scheduleCollector (PROCESS_NEWROOTBUFFER), |
| Phase.scheduleMutator (PROCESS_DECBUFFER), |
| Phase.scheduleGlobal (PROCESS_DECBUFFER), |
| Phase.scheduleCollector (PROCESS_DECBUFFER), |
| Phase.scheduleGlobal (BT_CLOSURE), |
| Phase.scheduleCollector (BT_CLOSURE)); |
| |
| /** |
| * Perform the initial determination of liveness from the roots. |
| */ |
| protected static final short rootClosurePhase = Phase.createComplex("initial-closure", null, |
| Phase.scheduleMutator (PREPARE), |
| Phase.scheduleGlobal (PREPARE), |
| Phase.scheduleCollector (PREPARE), |
| Phase.scheduleComplex (prepareStacks), |
| Phase.scheduleCollector (PRECOPY), |
| Phase.scheduleCollector (STACK_ROOTS), |
| Phase.scheduleCollector (ROOTS), |
| Phase.scheduleGlobal (ROOTS), |
| Phase.scheduleMutator (PROCESS_MODBUFFER), |
| Phase.scheduleGlobal (PROCESS_MODBUFFER), |
| Phase.scheduleCollector (PROCESS_MODBUFFER), |
| Phase.scheduleGlobal (CLOSURE), |
| Phase.scheduleCollector (CLOSURE)); |
| |
| /** |
| * This is the phase that is executed to perform a collection. |
| */ |
| public short collection = Phase.createComplex("collection", null, |
| Phase.scheduleComplex(initPhase), |
| Phase.scheduleComplex(rootClosurePhase), |
| Phase.scheduleComplex(refCountCollectionPhase), |
| Phase.scheduleComplex(completeClosurePhase), |
| Phase.scheduleComplex(finishPhase)); |
| |
| // CHECKSTYLE:ON |
| |
| /***************************************************************************** |
| * |
| * Class fields |
| */ |
| public static final ExplicitFreeListSpace rcSpace = new ExplicitFreeListSpace("rc", DEFAULT_POLL_FREQUENCY, VMRequest.create()); |
| public static final ExplicitLargeObjectSpace rcloSpace = new ExplicitLargeObjectSpace("rclos", DEFAULT_POLL_FREQUENCY, VMRequest.create()); |
| |
| public static final int REF_COUNT = rcSpace.getDescriptor(); |
| public static final int REF_COUNT_LOS = rcloSpace.getDescriptor(); |
| |
| public final SharedDeque modPool = new SharedDeque("mod", metaDataSpace, 1); |
| public final SharedDeque decPool = new SharedDeque("dec", metaDataSpace, 1); |
| public final SharedDeque newRootPool = new SharedDeque("newRoot", metaDataSpace, 1); |
| public final SharedDeque oldRootPool = new SharedDeque("oldRoot", metaDataSpace, 1); |
| |
| /***************************************************************************** |
| * |
| * Instance fields |
| */ |
| public final Trace rootTrace; |
| public final Trace backupTrace; |
| private final BTSweeper rcSweeper; |
| private final BTScanLargeObjectSweeper loScanSweeper; |
| private final BTFreeLargeObjectSweeper loFreeSweeper; |
| |
| /** |
| * Constructor |
| */ |
| public RCBase() { |
| Options.noReferenceTypes.setDefaultValue(true); |
| Options.noFinalizer.setDefaultValue(true); |
| |
| rootTrace = new Trace(metaDataSpace); |
| backupTrace = new Trace(metaDataSpace); |
| rcSweeper = new BTSweeper(); |
| loScanSweeper = new BTScanLargeObjectSweeper(); |
| loFreeSweeper = new BTFreeLargeObjectSweeper(); |
| } |
| |
| /** |
| * The boot method is called early in the boot process before any |
| * allocation. |
| */ |
| @Interruptible |
| public void postBoot() { |
| super.postBoot(); |
| |
| if (!Options.noReferenceTypes.getValue()) { |
| VM.assertions.fail("Reference Types are not supported by RC"); |
| } |
| if (!Options.noFinalizer.getValue()) { |
| VM.assertions.fail("Finalizers are not supported by RC"); |
| } |
| } |
| |
| /***************************************************************************** |
| * |
| * Collection |
| */ |
| |
| public static final boolean isRCObject(ObjectReference object) { |
| return !object.isNull() && !Space.isInSpace(VM_SPACE, object); |
| } |
| |
| /** |
| * @return Whether last GC is a full GC. |
| */ |
| public boolean lastCollectionFullHeap() { |
| return performCycleCollection; |
| } |
| |
| /** |
| * Perform a (global) collection phase. |
| * |
| * @param phaseId Collection phase |
| */ |
| public void collectionPhase(short phaseId) { |
| if (phaseId == SET_COLLECTION_KIND) { |
| super.collectionPhase(phaseId); |
| if (CC_ENABLED) { |
| performCycleCollection = (collectionAttempt > 1) || emergencyCollection || CC_FORCE_FULL; |
| if (performCycleCollection && Options.verbose.getValue() > 0) Log.write(" [CC] "); |
| } |
| return; |
| } |
| |
| if (phaseId == PREPARE) { |
| VM.finalizableProcessor.clear(); |
| VM.weakReferences.clear(); |
| VM.softReferences.clear(); |
| VM.phantomReferences.clear(); |
| rootTrace.prepare(); |
| rcSpace.prepare(); |
| if (CC_BACKUP_TRACE && performCycleCollection) { |
| backupTrace.prepare(); |
| } |
| return; |
| } |
| |
| if (phaseId == CLOSURE) { |
| rootTrace.prepare(); |
| return; |
| } |
| |
| if (phaseId == BT_CLOSURE) { |
| if (CC_BACKUP_TRACE && performCycleCollection) { |
| backupTrace.prepare(); |
| } |
| return; |
| } |
| |
| if (phaseId == PROCESS_OLDROOTBUFFER) { |
| oldRootPool.prepare(); |
| return; |
| } |
| |
| if (phaseId == PROCESS_NEWROOTBUFFER) { |
| newRootPool.prepare(); |
| return; |
| } |
| |
| |
| if (phaseId == PROCESS_MODBUFFER) { |
| modPool.prepare(); |
| return; |
| } |
| |
| if (phaseId == PROCESS_DECBUFFER) { |
| decPool.prepare(); |
| return; |
| } |
| |
| if (phaseId == RELEASE) { |
| rootTrace.release(); |
| if (CC_BACKUP_TRACE && performCycleCollection) { |
| backupTrace.release(); |
| rcSpace.sweepCells(rcSweeper); |
| rcloSpace.sweep(loScanSweeper); |
| rcloSpace.sweep(loFreeSweeper); |
| } else { |
| rcSpace.release(); |
| } |
| return; |
| } |
| |
| super.collectionPhase(phaseId); |
| } |
| |
| /***************************************************************************** |
| * |
| * Accounting |
| */ |
| |
| /** |
| * Return the number of pages used given the pending |
| * allocation. |
| * |
| * @return The number of pages reserved given the pending |
| * allocation, excluding space reserved for copying. |
| */ |
| public int getPagesUsed() { |
| return (rcSpace.reservedPages() + rcloSpace.reservedPages() + super.getPagesUsed()); |
| } |
| |
| /** |
| * Perform a linear scan across all objects in the heap to check for leaks. |
| */ |
| public void sanityLinearScan(LinearScan scan) { |
| //rcSpace.linearScan(scan); |
| } |
| |
| /** |
| * Return the expected reference count. For non-reference counting |
| * collectors this becomes a true/false relationship. |
| * |
| * @param object The object to check. |
| * @param sanityRootRC The number of root references to the object. |
| * @return The expected (root excluded) reference count. |
| */ |
| public int sanityExpectedRC(ObjectReference object, int sanityRootRC) { |
| if (RCBase.isRCObject(object)) { |
| int fullRC = RCHeader.getRC(object); |
| if (fullRC == 0) { |
| return SanityChecker.DEAD; |
| } |
| if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(fullRC >= sanityRootRC); |
| return fullRC - sanityRootRC; |
| } |
| return SanityChecker.ALIVE; |
| } |
| |
| /** |
| * Register specialized methods. |
| */ |
| @Interruptible |
| protected void registerSpecializedMethods() { |
| super.registerSpecializedMethods(); |
| } |
| } |