blob: 68373e42f46024d710114a55c7141e27d27d1237 [file] [log] [blame]
/*
* 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();
}
}