/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * 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/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.mmtk.plan.refcount.cd; import org.mmtk.plan.Phase; import org.mmtk.plan.refcount.RCBase; import org.mmtk.plan.refcount.RCHeader; import org.mmtk.utility.Log; import org.mmtk.utility.deque.SharedDeque; import org.mmtk.utility.options.Options; import org.mmtk.vm.VM; import org.vmmagic.pragma.*; import org.vmmagic.unboxed.*; /** * This class implements the global state of a trial deletion cycle detector. */ @Uninterruptible public final class TrialDeletion extends CD { /**************************************************************************** * * Class variables */ // Collection phases public static final short CD_PREPARE_FILTER = Phase.createSimple("td.prepare-filter"); public static final short CD_PREPARE_COLLECT = Phase.createSimple("td.prepare-collect"); public static final short CD_FILTER_PURPLE = Phase.createSimple("td.filter-purple"); public static final short CD_FREE_FILTERED = Phase.createSimple("td.free-filtered"); public static final short CD_FILTER_MATURE = Phase.createSimple("td.filter-mature"); public static final short CD_MARK_GREY = Phase.createSimple("td.mark-grey"); public static final short CD_SCAN = Phase.createSimple("td.scan"); public static final short CD_COLLECT = Phase.createSimple("td.collect"); public static final short CD_FREE = Phase.createSimple("td.free"); public static final short CD_FLUSH_FILTERED = Phase.createSimple("td.flush-filtered"); public static final short CD_PROCESS_DECS = Phase.createSimple("td.process-decs"); public static final short CD_RELEASE = Phase.createSimple("td.release"); // CHECKSTYLE:OFF /* Cycle detection */ private static final short cdPhase = Phase.createComplex("trial deletion", Phase.scheduleGlobal (CD_PREPARE_FILTER), Phase.scheduleCollector(CD_FILTER_PURPLE), Phase.scheduleCollector(CD_FREE_FILTERED), Phase.scheduleGlobal (CD_PREPARE_COLLECT), Phase.scheduleCollector(CD_FILTER_MATURE), Phase.scheduleCollector(CD_MARK_GREY), Phase.scheduleCollector(CD_SCAN), Phase.scheduleCollector(CD_COLLECT), Phase.scheduleCollector(CD_FREE), Phase.scheduleCollector(CD_FLUSH_FILTERED), Phase.scheduleCollector(CD_PROCESS_DECS), Phase.scheduleGlobal (CD_RELEASE)); // CHECKSTYLE:ON public static final int NO_PROCESSING = 0; public static final int FILTER_PURPLE = 1; public static final int FULL_COLLECTION = 2; /**************************************************************************** * * Instance variables */ public final SharedDeque workPool; public final SharedDeque blackPool; public final SharedDeque unfilteredPurplePool; public final SharedDeque maturePurplePool; public final SharedDeque filteredPurplePool; public final SharedDeque cyclePoolA; public final SharedDeque cyclePoolB; public final SharedDeque freePool; public int cdMode; private long startNanos; /**************************************************************************** * * Initialization */ public TrialDeletion(RCBase global) { workPool = new SharedDeque("workPool",RCBase.metaDataSpace, 1); blackPool = new SharedDeque("blackPool",RCBase.metaDataSpace, 1); unfilteredPurplePool = new SharedDeque("unfilteredPurplePool",RCBase.metaDataSpace, 1); maturePurplePool = new SharedDeque("maturePurplePool",RCBase.metaDataSpace, 1); filteredPurplePool = new SharedDeque("filteredPurplePool",RCBase.metaDataSpace, 1); cyclePoolA = new SharedDeque("cyclePoolA",RCBase.metaDataSpace, 1); cyclePoolB = new SharedDeque("cyclePoolB",RCBase.metaDataSpace, 1); freePool = new SharedDeque("freePool",RCBase.metaDataSpace, 1); cdMode = NO_PROCESSING; global.insertPhaseAfter(Phase.scheduleGlobal(RCBase.RELEASE), Phase.scheduleComplex(cdPhase)); } /** * Perform a (global) collection phase. * * @param phaseId Collection phase to execute. */ @Inline public boolean collectionPhase(int phaseId) { if (phaseId == CD_PREPARE_FILTER) { cdMode = NO_PROCESSING; if (shouldFilterPurple()) { cdMode = FILTER_PURPLE; } workPool.prepareNonBlocking(); blackPool.prepareNonBlocking(); filteredPurplePool.prepareNonBlocking(); cyclePoolA.prepareNonBlocking(); cyclePoolB.prepareNonBlocking(); maturePurplePool.prepare(); unfilteredPurplePool.prepare(); freePool.prepare(); return true; } if (phaseId == CD_PREPARE_COLLECT) { if (cdMode == FILTER_PURPLE) { if (shouldCollectCycles()) { cdMode = FULL_COLLECTION; startNanos = VM.statistics.nanoTime(); if (Options.verbose.getValue() > 0) { Log.write("(CD-TD "); Log.flush(); } } } return true; } if (phaseId == CD_RELEASE) { if (cdMode != NO_PROCESSING) { unfilteredPurplePool.reset(); } if (cdMode == FULL_COLLECTION) { workPool.reset(); blackPool.reset(); maturePurplePool.reset(); filteredPurplePool.reset(); cyclePoolA.reset(); cyclePoolB.reset(); freePool.reset(); if (Options.verbose.getValue() > 0) { Log.write(VM.statistics.nanosToMillis(VM.statistics.nanoTime() - startNanos)); Log.write(" ms)"); } } return true; } return false; } /***************************************************************************** * * Collection */ /** * Update the CD section of the RC word when an increment is performed * * @param rcWord The refcount word after the increment. * @return The updated status after CD modification */ public int notifyIncRC(int rcWord) { return (rcWord & ~RCHeader.PURPLE); } /** * If the reported decrement succeeds, should we buffer the object? * * @param rcWord The refcount work post decrement. * @return The updated status after CD modification */ public boolean shouldBufferOnDecRC(int rcWord) { return ((rcWord & RCHeader.COLOR_MASK) < RCHeader.PURPLE) && ((rcWord & RCHeader.BUFFERED_MASK) == 0); } /** * Allow a free of this object, or is it in a CD data structure * * @param object The object to check * @return True if free is safe */ public boolean allowFree(ObjectReference object) { return !RCHeader.isBuffered(object); } /** * Update the header on a buffered dec to non-zero RC * * @param rcWord The refcount work post decrement. * @return The updated status after CD modification */ public int updateHeaderOnBufferedDec(int rcWord) { return (rcWord & ~RCHeader.COLOR_MASK) | RCHeader.PURPLE | RCHeader.BUFFERED_MASK; } /** * Update the header on a non-buffered dec to non-zero RC * * @param rcWord The refcount work post decrement. * @return The updated status after CD modification */ public int updateHeaderOnUnbufferedDec(int rcWord) { if ((rcWord & RCHeader.GREEN) != 0) { return rcWord; } return (rcWord & ~RCHeader.COLOR_MASK) | RCHeader.PURPLE; } /** * Perform any cycle detector header initialization. * * @param typeRef Type information for the object. * @param rcWord The refcount work post decrement. * @return The updated status after CD modification */ public int initializeHeader(ObjectReference typeRef, int rcWord) { if (VM.objectModel.isAcyclic(typeRef)) { rcWord |= RCHeader.GREEN; } return rcWord; } }