| /* |
| * 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; |
| |
| import org.mmtk.policy.Space; |
| import org.mmtk.utility.Constants; |
| import org.mmtk.utility.Log; |
| import org.mmtk.utility.options.*; |
| import org.mmtk.utility.statistics.Timer; |
| import org.mmtk.vm.VM; |
| |
| import org.vmmagic.pragma.*; |
| |
| /** |
| * This abstract class implements the core functionality for |
| * simple collectors.<p> |
| * |
| * This class defines the collection phases, and provides base |
| * level implementations of them. Subclasses should provide |
| * implementations for the spaces that they introduce, and |
| * delegate up the class hierarchy.<p> |
| * |
| * For details of the split between global and thread-local operations |
| * @see org.mmtk.plan.Plan |
| */ |
| @Uninterruptible |
| public abstract class Simple extends Plan implements Constants { |
| /**************************************************************************** |
| * Constants |
| */ |
| |
| /* Shared Timers */ |
| private static final Timer refTypeTime = new Timer("refType", false, true); |
| private static final Timer scanTime = new Timer("scan", false, true); |
| private static final Timer finalizeTime = new Timer("finalize", false, true); |
| |
| /* Phases */ |
| public static final short SET_COLLECTION_KIND = Phase.createSimple("set-collection-kind", null); |
| public static final short INITIATE = Phase.createSimple("initiate", null); |
| public static final short PREPARE = Phase.createSimple("prepare"); |
| public static final short PRECOPY = Phase.createSimple("precopy"); |
| public static final short PREPARE_STACKS = Phase.createSimple("prepare-stacks", null); |
| public static final short STACK_ROOTS = Phase.createSimple("stacks"); |
| public static final short ROOTS = Phase.createSimple("root"); |
| public static final short CLOSURE = Phase.createSimple("closure", scanTime); |
| public static final short SOFT_REFS = Phase.createSimple("soft-ref", refTypeTime); |
| public static final short WEAK_REFS = Phase.createSimple("weak-ref", refTypeTime); |
| public static final short FINALIZABLE = Phase.createSimple("finalize", finalizeTime); |
| public static final short WEAK_TRACK_REFS = Phase.createSimple("weak-track-ref", refTypeTime); |
| public static final short PHANTOM_REFS = Phase.createSimple("phantom-ref", refTypeTime); |
| public static final short FORWARD = Phase.createSimple("forward"); |
| public static final short FORWARD_REFS = Phase.createSimple("forward-ref", refTypeTime); |
| public static final short FORWARD_FINALIZABLE = Phase.createSimple("forward-finalize", finalizeTime); |
| public static final short RELEASE = Phase.createSimple("release"); |
| public static final short COMPLETE = Phase.createSimple("complete", null); |
| |
| /* Sanity placeholder */ |
| public static final short PRE_SANITY_PLACEHOLDER = Phase.createSimple("pre-sanity-placeholder", null); |
| public static final short POST_SANITY_PLACEHOLDER = Phase.createSimple("post-sanity-placeholder", null); |
| |
| /* Sanity phases */ |
| public static final short SANITY_SET_PREGC = Phase.createSimple("sanity-setpre", null); |
| public static final short SANITY_SET_POSTGC = Phase.createSimple("sanity-setpost", null); |
| public static final short SANITY_PREPARE = Phase.createSimple("sanity-prepare", null); |
| public static final short SANITY_ROOTS = Phase.createSimple("sanity-roots", null); |
| public static final short SANITY_COPY_ROOTS = Phase.createSimple("sanity-copy-roots", null); |
| public static final short SANITY_BUILD_TABLE = Phase.createSimple("sanity-build-table", null); |
| public static final short SANITY_CHECK_TABLE = Phase.createSimple("sanity-check-table", null); |
| public static final short SANITY_RELEASE = Phase.createSimple("sanity-release", null); |
| |
| // CHECKSTYLE:OFF |
| |
| /** Ensure stacks are ready to be scanned */ |
| protected static final short prepareStacks = Phase.createComplex("prepare-stacks", null, |
| Phase.scheduleCollector (PREPARE_STACKS), |
| Phase.scheduleMutator (PREPARE_STACKS), |
| Phase.scheduleGlobal (PREPARE_STACKS)); |
| |
| /** Trace and set up a sanity table */ |
| protected static final short sanityBuildPhase = Phase.createComplex("sanity-build", null, |
| Phase.scheduleGlobal (SANITY_PREPARE), |
| Phase.scheduleCollector (SANITY_PREPARE), |
| Phase.scheduleComplex (prepareStacks), |
| Phase.scheduleCollector (SANITY_ROOTS), |
| Phase.scheduleGlobal (SANITY_ROOTS), |
| Phase.scheduleCollector (SANITY_COPY_ROOTS), |
| Phase.scheduleGlobal (SANITY_BUILD_TABLE)); |
| |
| /** Validate a sanity table */ |
| protected static final short sanityCheckPhase = Phase.createComplex("sanity-check", null, |
| Phase.scheduleGlobal (SANITY_CHECK_TABLE), |
| Phase.scheduleCollector (SANITY_RELEASE), |
| Phase.scheduleGlobal (SANITY_RELEASE)); |
| |
| /** Start the collection, including preparation for any collected spaces. */ |
| protected static final short initPhase = Phase.createComplex("init", |
| Phase.scheduleGlobal (SET_COLLECTION_KIND), |
| Phase.scheduleGlobal (INITIATE), |
| Phase.schedulePlaceholder(PRE_SANITY_PLACEHOLDER)); |
| |
| /** |
| * 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.scheduleGlobal (CLOSURE), |
| Phase.scheduleCollector (CLOSURE)); |
| |
| /** |
| * Complete closure including reference types and finalizable objects. |
| */ |
| protected static final short refTypeClosurePhase = Phase.createComplex("refType-closure", null, |
| Phase.scheduleCollector (SOFT_REFS), |
| Phase.scheduleGlobal (CLOSURE), |
| Phase.scheduleCollector (CLOSURE), |
| Phase.scheduleCollector (WEAK_REFS), |
| Phase.scheduleCollector (FINALIZABLE), |
| Phase.scheduleGlobal (CLOSURE), |
| Phase.scheduleCollector (CLOSURE), |
| Phase.schedulePlaceholder(WEAK_TRACK_REFS), |
| Phase.scheduleCollector (PHANTOM_REFS)); |
| |
| /** |
| * Ensure that all references in the system are correct. |
| */ |
| protected static final short forwardPhase = Phase.createComplex("forward-all", null, |
| /* Finish up */ |
| Phase.schedulePlaceholder(FORWARD), |
| Phase.scheduleCollector (FORWARD_REFS), |
| Phase.scheduleCollector (FORWARD_FINALIZABLE)); |
| |
| /** |
| * Complete closure including reference types and finalizable objects. |
| */ |
| protected static final short completeClosurePhase = Phase.createComplex("release", null, |
| Phase.scheduleMutator (RELEASE), |
| Phase.scheduleCollector (RELEASE), |
| Phase.scheduleGlobal (RELEASE)); |
| |
| |
| /** |
| * The collection scheme - this is a small tree of complex phases. |
| */ |
| protected static final short finishPhase = Phase.createComplex("finish", |
| Phase.schedulePlaceholder(POST_SANITY_PLACEHOLDER), |
| Phase.scheduleCollector (COMPLETE), |
| Phase.scheduleGlobal (COMPLETE)); |
| |
| /** |
| * 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(refTypeClosurePhase), |
| Phase.scheduleComplex(forwardPhase), |
| Phase.scheduleComplex(completeClosurePhase), |
| Phase.scheduleComplex(finishPhase)); |
| |
| // CHECKSTYLE:ON |
| |
| /** |
| * The current collection attempt. |
| */ |
| protected int collectionAttempt; |
| |
| /**************************************************************************** |
| * Collection |
| */ |
| |
| /** |
| * Perform a (global) collection phase. |
| * |
| * @param phaseId The unique of the phase to perform. |
| */ |
| @Inline |
| public void collectionPhase(short phaseId) { |
| if (phaseId == SET_COLLECTION_KIND) { |
| requiredAtStart = getPagesRequired(); |
| collectionAttempt = VM.collection.maximumCollectionAttempt(); |
| emergencyCollection = lastCollectionWasExhaustive() && collectionAttempt > 1; |
| if (collectionAttempt > MAX_COLLECTION_ATTEMPTS) { |
| VM.assertions.fail("Too many collection attempts. Suspect plan is not setting FullHeap flag"); |
| } |
| if (emergencyCollection) { |
| if (Options.verbose.getValue() >= 1) Log.write("[Emergency]"); |
| forceFullHeapCollection(); |
| } |
| return; |
| } |
| |
| if (phaseId == INITIATE) { |
| setGCStatus(GC_PREPARE); |
| return; |
| } |
| |
| if (phaseId == PREPARE_STACKS) { |
| stacksPrepared = true; |
| return; |
| } |
| |
| if (phaseId == PREPARE) { |
| loSpace.prepare(true); |
| nonMovingSpace.prepare(true); |
| if (USE_CODE_SPACE) { |
| smallCodeSpace.prepare(true); |
| largeCodeSpace.prepare(true); |
| } |
| immortalSpace.prepare(); |
| VM.memory.globalPrepareVMSpace(); |
| return; |
| } |
| |
| if (phaseId == ROOTS) { |
| VM.scanning.resetThreadCounter(); |
| setGCStatus(GC_PROPER); |
| return; |
| } |
| |
| if (phaseId == RELEASE) { |
| loSpace.release(true); |
| nonMovingSpace.release(); |
| if (USE_CODE_SPACE) { |
| smallCodeSpace.release(); |
| largeCodeSpace.release(true); |
| } |
| immortalSpace.release(); |
| VM.memory.globalReleaseVMSpace(); |
| return; |
| } |
| |
| if (phaseId == COMPLETE) { |
| setGCStatus(NOT_IN_GC); |
| Space.clearAllAllocationFailed(); |
| awaitingAsyncCollection = false; |
| return; |
| } |
| |
| if (Options.sanityCheck.getValue() && sanityChecker.collectionPhase(phaseId)) { |
| return; |
| } |
| |
| Log.write("Global phase "); Log.write(Phase.getName(phaseId)); |
| Log.writeln(" not handled."); |
| VM.assertions.fail("Global phase not handled!"); |
| } |
| |
| /** |
| * Replace a scheduled phase. Used for example to replace a placeholder. |
| * |
| * @param oldScheduledPhase The scheduled phase to replace. |
| * @param newScheduledPhase The new scheduled phase. |
| */ |
| public void replacePhase(int oldScheduledPhase, int newScheduledPhase) { |
| ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection); |
| cp.replacePhase(oldScheduledPhase, newScheduledPhase); |
| } |
| |
| /** |
| * Replace a placeholder phase. |
| * |
| * @param placeHolderPhase The placeholder phase |
| * @param newScheduledPhase The new scheduled phase. |
| */ |
| public void replacePlaceholderPhase(short placeHolderPhase, int newScheduledPhase) { |
| ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection); |
| cp.replacePhase(Phase.schedulePlaceholder(placeHolderPhase), newScheduledPhase); |
| } |
| } |