/** * Return the number of metadata pages reserved for use given the pending allocation. * * @return The number of pages reserved given the pending allocation, excluding space reserved for * copying. */ public int getMetaDataPagesUsed() { return metaDataSpace.reservedPages(); }
/** * Return the number of pages reserved for use given the pending allocation. * * @return The number of pages reserved given the pending allocation, excluding space reserved for * copying. */ public int getPagesUsed() { return loSpace.reservedPages() + immortalSpace.reservedPages() + metaDataSpace.reservedPages() + nonMovingSpace.reservedPages(); }
/** * Calculate the number of pages a collection is required to free to satisfy outstanding * allocation requests. * * @return the number of pages a collection is required to free to satisfy outstanding allocation * requests. */ public int getPagesRequired() { return loSpace.requiredPages() + metaDataSpace.requiredPages() + immortalSpace.requiredPages() + nonMovingSpace.requiredPages(); }
/** * This abstract class implements the global core functionality for all memory management schemes. * All global MMTk plans should inherit from this class. * * <p>All plans make a clear distinction between <i>global</i> and <i>thread-local</i> activities, * and divides global and local state into separate class hierarchies. Global activities must be * synchronized, whereas no synchronization is required for thread-local activities. There is a * single instance of Plan (or the appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel * threads" (aka CPUs). Thus instance methods of PlanLocal allow fast, unsynchronized access to * functions such as allocation and collection. * * <p>The global instance defines and manages static resources (such as memory and virtual memory * resources). This mapping of threads to instances is crucial to understanding the correctness and * performance properties of MMTk plans. */ @Uninterruptible public abstract class Plan implements Constants { /** ************************************************************************** Constants */ /* GC State */ public static final int NOT_IN_GC = 0; // this must be zero for C code public static final int GC_PREPARE = 1; // before setup and obtaining root public static final int GC_PROPER = 2; /* Polling */ public static final int DEFAULT_POLL_FREQUENCY = (128 << 10) >> LOG_BYTES_IN_PAGE; public static final int META_DATA_POLL_FREQUENCY = DEFAULT_POLL_FREQUENCY; /* Space Size Constants. */ public static final boolean USE_CODE_SPACE = true; public static final float PLOS_FRAC = 0.07f; public static final int HEAP_FULL_MINIMUM = (1 << 17) >> LOG_BYTES_IN_PAGE; // 128K public static final int HEAP_FULL_PERCENTAGE = 2; /* Allocator Constants */ public static final int ALLOC_DEFAULT = 0; public static final int ALLOC_NON_REFERENCE = 1; public static final int ALLOC_NON_MOVING = 2; public static final int ALLOC_IMMORTAL = 3; public static final int ALLOC_LOS = 4; public static final int ALLOC_PRIMITIVE_LOS = 5; public static final int ALLOC_GCSPY = 6; public static final int ALLOC_CODE = 7; public static final int ALLOC_LARGE_CODE = 8; public static final int ALLOC_HOT_CODE = USE_CODE_SPACE ? ALLOC_CODE : ALLOC_DEFAULT; public static final int ALLOC_COLD_CODE = USE_CODE_SPACE ? ALLOC_CODE : ALLOC_DEFAULT; public static final int ALLOC_STACK = ALLOC_LOS; public static final int ALLOCATORS = 9; public static final int DEFAULT_SITE = -1; /* Miscellaneous Constants */ // public static final int LOS_SIZE_THRESHOLD = SegregatedFreeListSpace.MAX_CELL_SIZE; public static final int NON_PARTICIPANT = 0; public static final boolean GATHER_WRITE_BARRIER_STATS = false; public static final int DEFAULT_MIN_NURSERY = (256 * 1024) >> LOG_BYTES_IN_PAGE; public static final int DEFAULT_MAX_NURSERY = (32 << 20) >> LOG_BYTES_IN_PAGE; public static final boolean SCAN_BOOT_IMAGE = true; // scan it for roots rather than trace it public static final int MAX_COLLECTION_ATTEMPTS = 10; // public static final boolean REQUIRES_LOS = VM.activePlan.constraints().requiresLOS(); public static final int MAX_NON_LOS_DEFAULT_ALLOC_BYTES = VM.activePlan.constraints().maxNonLOSDefaultAllocBytes(); public static final int MAX_NON_LOS_NONMOVING_ALLOC_BYTES = VM.activePlan.constraints().maxNonLOSNonMovingAllocBytes(); public static final int MAX_NON_LOS_COPY_BYTES = VM.activePlan.constraints().maxNonLOSCopyBytes(); /* Do we support a log bit in the object header? Some write barriers may use it */ public static final boolean NEEDS_LOG_BIT_IN_HEADER = VM.activePlan.constraints().needsLogBitInHeader(); /** ************************************************************************** Class variables */ /** The space that holds any VM specific objects (e.g. a boot image) */ public static final Space vmSpace = VM.memory.getVMSpace(); /** Any immortal objects allocated after booting are allocated here. */ public static final ImmortalSpace immortalSpace = new ImmortalSpace("immortal", DEFAULT_POLL_FREQUENCY, VMRequest.create()); /** All meta data that is used by MMTk is allocated (and accounted for) in the meta data space. */ public static final RawPageSpace metaDataSpace = new RawPageSpace("meta", DEFAULT_POLL_FREQUENCY, VMRequest.create()); /** Large objects are allocated into a special large object space. */ public static final LargeObjectSpace loSpace = new LargeObjectSpace("los", DEFAULT_POLL_FREQUENCY, VMRequest.create()); /** Space used by the sanity checker (used at runtime only if sanity checking enabled */ public static final RawPageSpace sanitySpace = new RawPageSpace("sanity", Integer.MAX_VALUE, VMRequest.create()); /** * Space used to allocate objects that cannot be moved. we do not need a large space as the LOS is * non-moving. */ public static final MarkSweepSpace nonMovingSpace = new MarkSweepSpace("non-moving", DEFAULT_POLL_FREQUENCY, VMRequest.create()); public static final MarkSweepSpace smallCodeSpace = USE_CODE_SPACE ? new MarkSweepSpace("sm-code", DEFAULT_POLL_FREQUENCY, VMRequest.create()) : null; public static final LargeObjectSpace largeCodeSpace = USE_CODE_SPACE ? new LargeObjectSpace("lg-code", DEFAULT_POLL_FREQUENCY, VMRequest.create()) : null; /* Space descriptors */ public static final int IMMORTAL = immortalSpace.getDescriptor(); public static final int VM_SPACE = vmSpace.getDescriptor(); public static final int META = metaDataSpace.getDescriptor(); public static final int LOS = loSpace.getDescriptor(); public static final int SANITY = sanitySpace.getDescriptor(); public static final int NON_MOVING = nonMovingSpace.getDescriptor(); public static final int SMALL_CODE = USE_CODE_SPACE ? smallCodeSpace.getDescriptor() : 0; public static final int LARGE_CODE = USE_CODE_SPACE ? largeCodeSpace.getDescriptor() : 0; /** Timer that counts total time */ public static final Timer totalTime = new Timer("time"); /** Support for time-limited GCs */ protected static long timeCap; /** Support for allocation-site identification */ protected static int allocationSiteCount = 0; /** Global sanity checking state * */ public static final SanityChecker sanityChecker = new SanityChecker(); /** ************************************************************************** Constructor. */ public Plan() { /* Create base option instances */ Options.verbose = new Verbose(); Options.verboseTiming = new VerboseTiming(); Options.stressFactor = new StressFactor(); Options.noFinalizer = new NoFinalizer(); Options.noReferenceTypes = new NoReferenceTypes(); Options.fullHeapSystemGC = new FullHeapSystemGC(); Options.harnessAll = new HarnessAll(); Options.ignoreSystemGC = new IgnoreSystemGC(); Options.metaDataLimit = new MetaDataLimit(); Options.nurserySize = new NurserySize(); Options.variableSizeHeap = new VariableSizeHeap(); Options.eagerMmapSpaces = new EagerMmapSpaces(); Options.sanityCheck = new SanityCheck(); Options.debugAddress = new DebugAddress(); Options.perfEvents = new PerfEvents(); Map.finalizeStaticSpaceMap(); registerSpecializedMethods(); } /** ************************************************************************** Boot. */ /** The boot method is called early in the boot process before any allocation. */ @Interruptible public void boot() {} /** * The postBoot method is called by the runtime immediately after command-line arguments are * available. Note that allocation must be supported prior to this point because the runtime * infrastructure may require allocation in order to parse the command line arguments. For this * reason all plans should operate gracefully on the default minimum heap size until the point * that boot is called. */ @Interruptible public void postBoot() { VM.statistics.perfEventInit(Options.perfEvents.getValue()); if (Options.verbose.getValue() > 2) Space.printVMMap(); if (Options.verbose.getValue() > 3) VM.config.printConfig(); if (Options.verbose.getValue() > 0) Stats.startAll(); if (Options.eagerMmapSpaces.getValue()) Space.eagerlyMmapMMTkSpaces(); } /** The fullyBooted method is called by the runtime just before normal execution commences. */ @Interruptible public void fullyBooted() { initialized = true; if (Options.harnessAll.getValue()) harnessBegin(); } /** * The VM is about to exit. Perform any clean up operations. * * @param value The exit value */ @Interruptible public void notifyExit(int value) { if (Options.harnessAll.getValue()) harnessEnd(); if (Options.verbose.getValue() == 1) { Log.write("[End "); totalTime.printTotalSecs(); Log.writeln(" s]"); } else if (Options.verbose.getValue() == 2) { Log.write("[End "); totalTime.printTotalMillis(); Log.writeln(" ms]"); } if (Options.verboseTiming.getValue()) printDetailedTiming(true); } /** * Any Plan can override this to provide additional plan specific timing information. * * @param totals Print totals */ protected void printDetailedTiming(boolean totals) {} /** * Perform any required write barrier action when installing an object reference a boot time. * * @param reference the reference value that is to be stored * @return The raw value to be */ public Word bootTimeWriteBarrier(Word reference) { return reference; } /** ************************************************************************** Allocation */ public static int getAllocationSite(boolean compileTime) { if (compileTime) // a new allocation site is being compiled return allocationSiteCount++; else // an anonymous site return DEFAULT_SITE; } /** ************************************************************************** Collection. */ /** Perform a (global) collection phase. */ public abstract void collectionPhase(short phase); /** * Replace a phase. * * @param oldScheduledPhase The scheduled phase to insert after * @param scheduledPhase The scheduled phase to insert */ @Interruptible public void replacePhase(int oldScheduledPhase, int scheduledPhase) { VM.assertions.fail("replacePhase not implemented for this plan"); } /** * Insert a phase. * * @param markerScheduledPhase The scheduled phase to insert after * @param scheduledPhase The scheduled phase to insert */ @Interruptible public void insertPhaseAfter(int markerScheduledPhase, int scheduledPhase) { short tempPhase = Phase.createComplex("auto-gen", null, markerScheduledPhase, scheduledPhase); replacePhase(markerScheduledPhase, Phase.scheduleComplex(tempPhase)); } /** * @return Whether last GC was an exhaustive attempt to collect the heap. For many collectors this * is the same as asking whether the last GC was a full heap collection. */ public boolean lastCollectionWasExhaustive() { return lastCollectionFullHeap(); } /** @return Whether last GC is a full GC. */ public boolean lastCollectionFullHeap() { return true; } /** @return Is last GC a full collection? */ public static boolean isEmergencyCollection() { return emergencyCollection; } /** @return True if we have run out of heap space. */ public final boolean lastCollectionFailed() { return !(collectionTrigger == Collection.EXTERNAL_GC_TRIGGER || collectionTrigger == Collection.INTERNAL_PHASE_GC_TRIGGER) && (getPagesAvail() < getHeapFullThreshold() || getPagesAvail() < requiredAtStart); } /** Force the next collection to be full heap. */ public void forceFullHeapCollection() {} /** @return Is current GC only collecting objects allocated since last GC. */ public boolean isCurrentGCNursery() { return false; } private long lastStressPages = 0; /** * 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) { Space space = Space.getSpaceForObject(object); return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD; } /** * Perform a linear scan of all spaces to check for possible leaks. This is only called after a * full-heap GC. * * @param scanner The scanner callback to use. */ public void sanityLinearScan(LinearScan scanner) {} /** @return True is a stress test GC is required */ @Inline public final boolean stressTestGCRequired() { long pages = Space.cumulativeCommittedPages(); if (initialized && ((pages ^ lastStressPages) > Options.stressFactor.getPages())) { lastStressPages = pages; return true; } else return false; } /** ************************************************************************** GC State */ protected static int requiredAtStart; protected static int collectionTrigger; protected static boolean emergencyCollection; protected static boolean awaitingAsyncCollection; protected static boolean stacksPrepared; private static boolean initialized = false; private static boolean collectionTriggered; @Entrypoint private static int gcStatus = NOT_IN_GC; // shared variable /** @return Is the memory management system initialized? */ public static boolean isInitialized() { return initialized; } /** Has collection has triggered? */ public static boolean isCollectionTriggered() { return collectionTriggered; } /** Set that a collection has been triggered. */ public static void setCollectionTriggered() { collectionTriggered = true; } /** A collection has fully completed. Clear the triggered flag. */ public static void collectionComplete() { collectionTriggered = false; } /** * Return true if stacks have been prepared in this collection cycle. * * @return True if stacks have been prepared in this collection cycle. */ public static boolean stacksPrepared() { return stacksPrepared; } /** * Return true if a collection is in progress. * * @return True if a collection is in progress. */ public static boolean gcInProgress() { return gcStatus != NOT_IN_GC; } /** * Return true if a collection is in progress and past the preparatory stage. * * @return True if a collection is in progress and past the preparatory stage. */ public static boolean gcInProgressProper() { return gcStatus == GC_PROPER; } /** * Sets the GC status. * * @param s The new GC status. */ public static void setGCStatus(int s) { if (gcStatus == NOT_IN_GC) { /* From NOT_IN_GC to any phase */ stacksPrepared = false; if (Stats.gatheringStats()) { Stats.startGC(); VM.activePlan.global().printPreStats(); } } VM.memory.isync(); gcStatus = s; VM.memory.sync(); if (gcStatus == NOT_IN_GC) { /* From any phase to NOT_IN_GC */ if (Stats.gatheringStats()) { Stats.endGC(); VM.activePlan.global().printPostStats(); } } } /** Print out statistics at the start of a GC */ public void printPreStats() { if ((Options.verbose.getValue() == 1) || (Options.verbose.getValue() == 2)) { Log.write("[GC "); Log.write(Stats.gcCount()); if (Options.verbose.getValue() == 1) { Log.write(" Start "); Plan.totalTime.printTotalSecs(); Log.write(" s"); } else { Log.write(" Start "); Plan.totalTime.printTotalMillis(); Log.write(" ms"); } Log.write(" "); Log.write(Conversions.pagesToKBytes(getPagesUsed())); Log.write("KB "); Log.flush(); } if (Options.verbose.getValue() > 2) { Log.write("Collection "); Log.write(Stats.gcCount()); Log.write(": "); printUsedPages(); Log.write(" Before Collection: "); Space.printUsageMB(); if (Options.verbose.getValue() >= 4) { Log.write(" "); Space.printUsagePages(); } if (Options.verbose.getValue() >= 5) { Space.printVMMap(); } } } /** Print out statistics at the end of a GC */ public final void printPostStats() { if ((Options.verbose.getValue() == 1) || (Options.verbose.getValue() == 2)) { Log.write("-> "); Log.writeDec(Conversions.pagesToBytes(getPagesUsed()).toWord().rshl(10)); Log.write("KB "); if (Options.verbose.getValue() == 1) { totalTime.printLast(); Log.writeln(" ms]"); } else { Log.write("End "); totalTime.printTotal(); Log.writeln(" ms]"); } } if (Options.verbose.getValue() > 2) { Log.write(" After Collection: "); Space.printUsageMB(); if (Options.verbose.getValue() >= 4) { Log.write(" "); Space.printUsagePages(); } if (Options.verbose.getValue() >= 5) { Space.printVMMap(); } Log.write(" "); printUsedPages(); Log.write(" Collection time: "); totalTime.printLast(); Log.writeln(" ms"); } } public final void printUsedPages() { Log.write("reserved = "); Log.write(Conversions.pagesToMBytes(getPagesReserved())); Log.write(" MB ("); Log.write(getPagesReserved()); Log.write(" pgs)"); Log.write(" total = "); Log.write(Conversions.pagesToMBytes(getTotalPages())); Log.write(" MB ("); Log.write(getTotalPages()); Log.write(" pgs)"); Log.writeln(); } /** Set the collection trigger. */ public static void setCollectionTrigger(int trigger) { collectionTrigger = trigger; } /** ************************************************************************** Harness */ protected static boolean insideHarness = false; /** * Generic hook to allow benchmarks to be harnessed. A plan may use this to perform certain * actions prior to the commencement of a benchmark, such as a full heap collection, turning on * instrumentation, etc. By default we do a full heap GC, and then start stats collection. */ @Interruptible public static void harnessBegin() { // Save old values. boolean oldFullHeap = Options.fullHeapSystemGC.getValue(); boolean oldIgnore = Options.ignoreSystemGC.getValue(); // Set desired values. Options.fullHeapSystemGC.setValue(true); Options.ignoreSystemGC.setValue(false); // Trigger a full heap GC. System.gc(); // Restore old values. Options.ignoreSystemGC.setValue(oldIgnore); Options.fullHeapSystemGC.setValue(oldFullHeap); // Start statistics insideHarness = true; Stats.startAll(); VM.activePlan.global().planHarnessBegin(); } public void planHarnessBegin() { // default empty } /** * Generic hook to allow benchmarks to be harnessed. A plan may use this to perform certain * actions after the completion of a benchmark, such as a full heap collection, turning off * instrumentation, etc. By default we stop all statistics objects and print their values. */ @Interruptible public static void harnessEnd() { Stats.stopAll(); insideHarness = false; } /** ************************************************************************** VM Accounting */ /* Global accounting and static access */ /** * Return the amount of <i>free memory</i>, in bytes (where free is defined as not in use). Note * that this may overstate the amount of <i>available memory</i>, which must account for unused * memory that is held in reserve for copying, and therefore unavailable for allocation. * * @return The amount of <i>free memory</i>, in bytes (where free is defined as not in use). */ public static Extent freeMemory() { return totalMemory().minus(usedMemory()); } /** * Return the amount of <i>available memory</i>, in bytes. Note that this accounts for unused * memory that is held in reserve for copying, and therefore unavailable for allocation. * * @return The amount of <i>available memory</i>, in bytes. */ public static Extent availableMemory() { return totalMemory().minus(reservedMemory()); } /** * Return the amount of <i>memory in use</i>, in bytes. Note that this excludes unused memory that * is held in reserve for copying, and therefore unavailable for allocation. * * @return The amount of <i>memory in use</i>, in bytes. */ public static Extent usedMemory() { return Conversions.pagesToBytes(VM.activePlan.global().getPagesUsed()); } /** * Return the amount of <i>memory in use</i>, in bytes. Note that this includes unused memory that * is held in reserve for copying, and therefore unavailable for allocation. * * @return The amount of <i>memory in use</i>, in bytes. */ public static Extent reservedMemory() { return Conversions.pagesToBytes(VM.activePlan.global().getPagesReserved()); } /** * Return the total amount of memory managed to the memory management system, in bytes. * * @return The total amount of memory managed to the memory management system, in bytes. */ public static Extent totalMemory() { return HeapGrowthManager.getCurrentHeapSize(); } /* Instance methods */ /** * Return the total amount of memory managed to the memory management system, in pages. * * @return The total amount of memory managed to the memory management system, in pages. */ public final int getTotalPages() { return totalMemory().toWord().rshl(LOG_BYTES_IN_PAGE).toInt(); } /** * Return the number of pages available for allocation. * * @return The number of pages available for allocation. */ public int getPagesAvail() { return getTotalPages() - getPagesReserved(); } /** * Return the number of pages reserved for use given the pending allocation. Sub-classes must * override the getCopyReserve method, as the arithmetic here is fixed. * * @return The number of pages reserved given the pending allocation, including space reserved for * copying. */ public final int getPagesReserved() { return getPagesUsed() + getCollectionReserve(); } /** * Return the number of pages reserved for collection. In most cases this is a copy reserve, all * subclasses that manage a copying space must add the copying contribution. * * @return The number of pages reserved given the pending allocation, including space reserved for * collection. */ public int getCollectionReserve() { return 0; } /** * Return the number of pages reserved for use given the pending allocation. * * @return The number of pages reserved given the pending allocation, excluding space reserved for * copying. */ public int getPagesUsed() { return loSpace.reservedPages() + immortalSpace.reservedPages() + metaDataSpace.reservedPages() + nonMovingSpace.reservedPages(); } /** * Calculate the number of pages a collection is required to free to satisfy outstanding * allocation requests. * * @return the number of pages a collection is required to free to satisfy outstanding allocation * requests. */ public int getPagesRequired() { return loSpace.requiredPages() + metaDataSpace.requiredPages() + immortalSpace.requiredPages() + nonMovingSpace.requiredPages(); } /** * The minimum number of pages a GC must have available after a collection for us to consider the * collection successful. */ public int getHeapFullThreshold() { int threshold = (getTotalPages() * HEAP_FULL_PERCENTAGE) / 100; if (threshold < HEAP_FULL_MINIMUM) threshold = HEAP_FULL_MINIMUM; return threshold; } /** * Return the number of metadata pages reserved for use given the pending allocation. * * @return The number of pages reserved given the pending allocation, excluding space reserved for * copying. */ public int getMetaDataPagesUsed() { return metaDataSpace.reservedPages(); } /** * Return the cycle time at which this GC should complete. * * @return The time cap for this GC (i.e. the time by which it should complete). */ public static long getTimeCap() { return timeCap; } /** * ************************************************************************** Internal read/write * barriers. */ /** * Store an object reference * * @param slot The location of the reference * @param value The value to store */ @Inline public void storeObjectReference(Address slot, ObjectReference value) { slot.store(value); } /** * Load an object reference * * @param slot The location of the reference * @return the object reference loaded from slot */ @Inline public ObjectReference loadObjectReference(Address slot) { return slot.loadObjectReference(); } /** ************************************************************************** Collection. */ /** * This method is called periodically by the allocation subsystem (by default, each time a page is * consumed), and provides the collector with an opportunity to collect. * * @param spaceFull Space request failed, must recover pages within 'space'. * @param space The space that triggered the poll. * @return true if a collection is required. */ @LogicallyUninterruptible public final boolean poll(boolean spaceFull, Space space) { if (isCollectionTriggered()) { if (space == metaDataSpace) { /* This is not, in general, in a GC safe point. */ return false; } /* Someone else initiated a collection, we should join it */ logPoll(space, "Joining collection"); VM.collection.joinCollection(); return true; } if (collectionRequired(spaceFull)) { if (space == metaDataSpace) { /* In general we must not trigger a GC on metadata allocation since * this is not, in general, in a GC safe point. Instead we initiate * an asynchronous GC, which will occur at the next safe point. */ logPoll(space, "Asynchronous collection requested"); setAwaitingAsyncCollection(); return false; } logPoll(space, "Triggering collection"); VM.collection.triggerCollection(Collection.RESOURCE_GC_TRIGGER); return true; } if (concurrentCollectionRequired()) { logPoll(space, "Triggering collection"); VM.collection.triggerCollection(Collection.INTERNAL_PHASE_GC_TRIGGER); return true; } return false; } /** * Check whether an asynchronous collection is pending. * * <p>This is decoupled from the poll() mechanism because the triggering of asynchronous * collections can trigger write barriers, which can trigger an asynchronous collection. Thus, if * the triggering were tightly coupled with the request to alloc() within the write buffer code, * then inifinite regress could result. There is no race condition in the following code since * there is no harm in triggering the collection more than once, thus it is unsynchronized. */ @Inline public static void checkForAsyncCollection() { if (awaitingAsyncCollection && VM.collection.noThreadsInGC()) { awaitingAsyncCollection = false; VM.collection.triggerAsyncCollection(Collection.RESOURCE_GC_TRIGGER); } } /** Request an async GC */ protected static void setAwaitingAsyncCollection() { awaitingAsyncCollection = true; } /** * Log a message from within 'poll' * * @param space * @param message */ private void logPoll(Space space, String message) { if (Options.verbose.getValue() >= 3) { Log.write(" [POLL] "); Log.write(space.getName()); Log.write(": "); Log.writeln(message); } } /** * This method controls the triggering of a GC. It is called periodically during allocation. * Returns true to trigger a collection. * * @param spaceFull Space request failed, must recover pages within 'space'. * @return True if a collection is requested by the plan. */ protected boolean collectionRequired(boolean spaceFull) { boolean stressForceGC = stressTestGCRequired(); boolean heapFull = getPagesReserved() > getTotalPages(); return spaceFull || stressForceGC || heapFull; } /** * This method controls the triggering of an atomic phase of a concurrent collection. It is called * periodically during allocation. * * @return True if a collection is requested by the plan. */ protected boolean concurrentCollectionRequired() { return false; } /** * Start GCspy server. * * @param port The port to listen on, * @param wait Should we wait for a client to connect? */ @Interruptible public void startGCspyServer(int port, boolean wait) { VM.assertions.fail("startGCspyServer called on non GCspy plan"); } /** * Can this object ever move. Used by the VM to make decisions about whether it needs to copy IO * buffers etc. * * @param object The object in question * @return True if it is not possible that the object will ever move. */ public boolean willNeverMove(ObjectReference object) { if (!VM.activePlan.constraints().movesObjects()) return true; if (Space.isInSpace(LOS, object)) return true; if (Space.isInSpace(IMMORTAL, object)) return true; if (Space.isInSpace(VM_SPACE, object)) return true; if (Space.isInSpace(NON_MOVING, object)) return true; if (USE_CODE_SPACE && Space.isInSpace(SMALL_CODE, object)) return true; if (USE_CODE_SPACE && Space.isInSpace(LARGE_CODE, object)) return true; /* * Default to false- this preserves correctness over efficiency. * Individual plans should override for non-moving spaces they define. */ return false; } /** * ************************************************************************** Specialized Methods */ /** Register specialized methods. */ @Interruptible protected void registerSpecializedMethods() {} /** Get the specialized scan with the given id. */ public final Class<?> getSpecializedScanClass(int id) { return TransitiveClosure.getSpecializedScanClass(id); } }