/* * 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); } }